diff options
Diffstat (limited to 'gcc/fortran/resolve.cc')
-rw-r--r-- | gcc/fortran/resolve.cc | 17582 |
1 files changed, 17582 insertions, 0 deletions
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc new file mode 100644 index 0000000..43eeefe --- /dev/null +++ b/gcc/fortran/resolve.cc @@ -0,0 +1,17582 @@ +/* Perform type resolution on the various structures. + Copyright (C) 2001-2022 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "options.h" +#include "bitmap.h" +#include "gfortran.h" +#include "arith.h" /* For gfc_compare_expr(). */ +#include "dependency.h" +#include "data.h" +#include "target-memory.h" /* for gfc_simplify_transfer */ +#include "constructor.h" + +/* Types used in equivalence statements. */ + +enum seq_type +{ + SEQ_NONDEFAULT, SEQ_NUMERIC, SEQ_CHARACTER, SEQ_MIXED +}; + +/* Stack to keep track of the nesting of blocks as we move through the + code. See resolve_branch() and gfc_resolve_code(). */ + +typedef struct code_stack +{ + struct gfc_code *head, *current; + struct code_stack *prev; + + /* This bitmap keeps track of the targets valid for a branch from + inside this block except for END {IF|SELECT}s of enclosing + blocks. */ + bitmap reachable_labels; +} +code_stack; + +static code_stack *cs_base = NULL; + + +/* Nonzero if we're inside a FORALL or DO CONCURRENT block. */ + +static int forall_flag; +int gfc_do_concurrent_flag; + +/* True when we are resolving an expression that is an actual argument to + a procedure. */ +static bool actual_arg = false; +/* True when we are resolving an expression that is the first actual argument + to a procedure. */ +static bool first_actual_arg = false; + + +/* Nonzero if we're inside a OpenMP WORKSHARE or PARALLEL WORKSHARE block. */ + +static int omp_workshare_flag; + +/* True if we are processing a formal arglist. The corresponding function + resets the flag each time that it is read. */ +static bool formal_arg_flag = false; + +/* True if we are resolving a specification expression. */ +static bool specification_expr = false; + +/* The id of the last entry seen. */ +static int current_entry_id; + +/* We use bitmaps to determine if a branch target is valid. */ +static bitmap_obstack labels_obstack; + +/* True when simplifying a EXPR_VARIABLE argument to an inquiry function. */ +static bool inquiry_argument = false; + + +bool +gfc_is_formal_arg (void) +{ + return formal_arg_flag; +} + +/* Is the symbol host associated? */ +static bool +is_sym_host_assoc (gfc_symbol *sym, gfc_namespace *ns) +{ + for (ns = ns->parent; ns; ns = ns->parent) + { + if (sym->ns == ns) + return true; + } + + return false; +} + +/* Ensure a typespec used is valid; for instance, TYPE(t) is invalid if t is + an ABSTRACT derived-type. If where is not NULL, an error message with that + locus is printed, optionally using name. */ + +static bool +resolve_typespec_used (gfc_typespec* ts, locus* where, const char* name) +{ + if (ts->type == BT_DERIVED && ts->u.derived->attr.abstract) + { + if (where) + { + if (name) + gfc_error ("%qs at %L is of the ABSTRACT type %qs", + name, where, ts->u.derived->name); + else + gfc_error ("ABSTRACT type %qs used at %L", + ts->u.derived->name, where); + } + + return false; + } + + return true; +} + + +static bool +check_proc_interface (gfc_symbol *ifc, locus *where) +{ + /* Several checks for F08:C1216. */ + if (ifc->attr.procedure) + { + gfc_error ("Interface %qs at %L is declared " + "in a later PROCEDURE statement", ifc->name, where); + return false; + } + if (ifc->generic) + { + /* For generic interfaces, check if there is + a specific procedure with the same name. */ + gfc_interface *gen = ifc->generic; + while (gen && strcmp (gen->sym->name, ifc->name) != 0) + gen = gen->next; + if (!gen) + { + gfc_error ("Interface %qs at %L may not be generic", + ifc->name, where); + return false; + } + } + if (ifc->attr.proc == PROC_ST_FUNCTION) + { + gfc_error ("Interface %qs at %L may not be a statement function", + ifc->name, where); + return false; + } + if (gfc_is_intrinsic (ifc, 0, ifc->declared_at) + || gfc_is_intrinsic (ifc, 1, ifc->declared_at)) + ifc->attr.intrinsic = 1; + if (ifc->attr.intrinsic && !gfc_intrinsic_actual_ok (ifc->name, 0)) + { + gfc_error ("Intrinsic procedure %qs not allowed in " + "PROCEDURE statement at %L", ifc->name, where); + return false; + } + if (!ifc->attr.if_source && !ifc->attr.intrinsic && ifc->name[0] != '\0') + { + gfc_error ("Interface %qs at %L must be explicit", ifc->name, where); + return false; + } + return true; +} + + +static void resolve_symbol (gfc_symbol *sym); + + +/* Resolve the interface for a PROCEDURE declaration or procedure pointer. */ + +static bool +resolve_procedure_interface (gfc_symbol *sym) +{ + gfc_symbol *ifc = sym->ts.interface; + + if (!ifc) + return true; + + if (ifc == sym) + { + gfc_error ("PROCEDURE %qs at %L may not be used as its own interface", + sym->name, &sym->declared_at); + return false; + } + if (!check_proc_interface (ifc, &sym->declared_at)) + return false; + + if (ifc->attr.if_source || ifc->attr.intrinsic) + { + /* Resolve interface and copy attributes. */ + resolve_symbol (ifc); + if (ifc->attr.intrinsic) + gfc_resolve_intrinsic (ifc, &ifc->declared_at); + + if (ifc->result) + { + sym->ts = ifc->result->ts; + sym->attr.allocatable = ifc->result->attr.allocatable; + sym->attr.pointer = ifc->result->attr.pointer; + sym->attr.dimension = ifc->result->attr.dimension; + sym->attr.class_ok = ifc->result->attr.class_ok; + sym->as = gfc_copy_array_spec (ifc->result->as); + sym->result = sym; + } + else + { + sym->ts = ifc->ts; + sym->attr.allocatable = ifc->attr.allocatable; + sym->attr.pointer = ifc->attr.pointer; + sym->attr.dimension = ifc->attr.dimension; + sym->attr.class_ok = ifc->attr.class_ok; + sym->as = gfc_copy_array_spec (ifc->as); + } + sym->ts.interface = ifc; + sym->attr.function = ifc->attr.function; + sym->attr.subroutine = ifc->attr.subroutine; + + sym->attr.pure = ifc->attr.pure; + sym->attr.elemental = ifc->attr.elemental; + sym->attr.contiguous = ifc->attr.contiguous; + sym->attr.recursive = ifc->attr.recursive; + sym->attr.always_explicit = ifc->attr.always_explicit; + sym->attr.ext_attr |= ifc->attr.ext_attr; + sym->attr.is_bind_c = ifc->attr.is_bind_c; + /* Copy char length. */ + if (ifc->ts.type == BT_CHARACTER && ifc->ts.u.cl) + { + sym->ts.u.cl = gfc_new_charlen (sym->ns, ifc->ts.u.cl); + if (sym->ts.u.cl->length && !sym->ts.u.cl->resolved + && !gfc_resolve_expr (sym->ts.u.cl->length)) + return false; + } + } + + return true; +} + + +/* 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. */ + +void +gfc_resolve_formal_arglist (gfc_symbol *proc) +{ + gfc_formal_arglist *f; + gfc_symbol *sym; + bool saved_specification_expr; + int i; + + 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; + sym->attr.always_explicit = 1; + } + + formal_arg_flag = true; + + for (f = proc->formal; f; f = f->next) + { + gfc_array_spec *as; + + sym = f->sym; + + if (sym == NULL) + { + /* Alternate return placeholder. */ + if (gfc_elemental (proc)) + gfc_error ("Alternate return specifier in elemental subroutine " + "%qs at %L is not allowed", proc->name, + &proc->declared_at); + if (proc->attr.function) + gfc_error ("Alternate return specifier in function " + "%qs at %L is not allowed", proc->name, + &proc->declared_at); + continue; + } + else if (sym->attr.procedure && sym->attr.if_source != IFSRC_DECL + && !resolve_procedure_interface (sym)) + return; + + if (strcmp (proc->name, sym->name) == 0) + { + gfc_error ("Self-referential argument " + "%qs at %L is not allowed", sym->name, + &proc->declared_at); + return; + } + + if (sym->attr.if_source != IFSRC_UNKNOWN) + gfc_resolve_formal_arglist (sym); + + if (sym->attr.subroutine || sym->attr.external) + { + if (sym->attr.flavor == FL_UNKNOWN) + gfc_add_flavor (&sym->attr, FL_PROCEDURE, sym->name, &sym->declared_at); + } + else + { + if (sym->ts.type == BT_UNKNOWN && !proc->attr.intrinsic + && (!sym->attr.function || sym->result == sym)) + gfc_set_default_type (sym, 1, sym->ns); + } + + as = sym->ts.type == BT_CLASS && sym->attr.class_ok + ? CLASS_DATA (sym)->as : sym->as; + + saved_specification_expr = specification_expr; + specification_expr = true; + gfc_resolve_array_spec (as, 0); + specification_expr = saved_specification_expr; + + /* 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 (as && as->rank > 0 && as->type == AS_DEFERRED + && ((sym->ts.type != BT_CLASS + && !(sym->attr.pointer || sym->attr.allocatable)) + || (sym->ts.type == BT_CLASS + && !(CLASS_DATA (sym)->attr.class_pointer + || CLASS_DATA (sym)->attr.allocatable))) + && sym->attr.flavor != FL_PROCEDURE) + { + as->type = AS_ASSUMED_SHAPE; + for (i = 0; i < as->rank; i++) + as->lower[i] = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1); + } + + if ((as && as->rank > 0 && as->type == AS_ASSUMED_SHAPE) + || (as && as->type == AS_ASSUMED_RANK) + || sym->attr.pointer || sym->attr.allocatable || sym->attr.target + || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && (CLASS_DATA (sym)->attr.class_pointer + || CLASS_DATA (sym)->attr.allocatable + || CLASS_DATA (sym)->attr.target)) + || sym->attr.optional) + { + proc->attr.always_explicit = 1; + if (proc->result) + proc->result->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->name, &sym->declared_at); + + if (gfc_pure (proc)) + { + if (sym->attr.flavor == FL_PROCEDURE) + { + /* F08:C1279. */ + if (!gfc_pure (sym)) + { + gfc_error ("Dummy procedure %qs of PURE procedure at %L must " + "also be PURE", sym->name, &sym->declared_at); + continue; + } + } + else if (!sym->attr.pointer) + { + if (proc->attr.function && sym->attr.intent != INTENT_IN) + { + if (sym->attr.value) + gfc_notify_std (GFC_STD_F2008, "Argument %qs" + " of pure function %qs at %L with VALUE " + "attribute but without INTENT(IN)", + sym->name, proc->name, &sym->declared_at); + else + gfc_error ("Argument %qs of pure function %qs at %L must " + "be INTENT(IN) or VALUE", sym->name, proc->name, + &sym->declared_at); + } + + if (proc->attr.subroutine && sym->attr.intent == INTENT_UNKNOWN) + { + if (sym->attr.value) + gfc_notify_std (GFC_STD_F2008, "Argument %qs" + " of pure subroutine %qs at %L with VALUE " + "attribute but without INTENT", sym->name, + proc->name, &sym->declared_at); + else + gfc_error ("Argument %qs of pure subroutine %qs at %L " + "must have its INTENT specified or have the " + "VALUE attribute", sym->name, proc->name, + &sym->declared_at); + } + } + + /* F08:C1278a. */ + if (sym->ts.type == BT_CLASS && sym->attr.intent == INTENT_OUT) + { + gfc_error ("INTENT(OUT) argument %qs of pure procedure %qs at %L" + " may not be polymorphic", sym->name, proc->name, + &sym->declared_at); + continue; + } + } + + if (proc->attr.implicit_pure) + { + if (sym->attr.flavor == FL_PROCEDURE) + { + if (!gfc_pure (sym)) + proc->attr.implicit_pure = 0; + } + else if (!sym->attr.pointer) + { + if (proc->attr.function && sym->attr.intent != INTENT_IN + && !sym->value) + proc->attr.implicit_pure = 0; + + if (proc->attr.subroutine && sym->attr.intent == INTENT_UNKNOWN + && !sym->value) + proc->attr.implicit_pure = 0; + } + } + + if (gfc_elemental (proc)) + { + /* F08:C1289. */ + if (sym->attr.codimension + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.codimension)) + { + gfc_error ("Coarray dummy argument %qs at %L to elemental " + "procedure", sym->name, &sym->declared_at); + continue; + } + + if (sym->as || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->as)) + { + gfc_error ("Argument %qs of elemental procedure at %L must " + "be scalar", sym->name, &sym->declared_at); + continue; + } + + if (sym->attr.allocatable + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.allocatable)) + { + gfc_error ("Argument %qs of elemental procedure at %L cannot " + "have the ALLOCATABLE attribute", sym->name, + &sym->declared_at); + continue; + } + + if (sym->attr.pointer + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.class_pointer)) + { + gfc_error ("Argument %qs of elemental procedure at %L cannot " + "have the POINTER attribute", sym->name, + &sym->declared_at); + continue; + } + + if (sym->attr.flavor == FL_PROCEDURE) + { + gfc_error ("Dummy procedure %qs not allowed in elemental " + "procedure %qs at %L", sym->name, proc->name, + &sym->declared_at); + continue; + } + + /* Fortran 2008 Corrigendum 1, C1290a. */ + if (sym->attr.intent == INTENT_UNKNOWN && !sym->attr.value) + { + gfc_error ("Argument %qs of elemental procedure %qs at %L must " + "have its INTENT specified or have the VALUE " + "attribute", sym->name, proc->name, + &sym->declared_at); + continue; + } + } + + /* Each dummy shall be specified to be scalar. */ + if (proc->attr.proc == PROC_ST_FUNCTION) + { + if (sym->as != NULL) + { + /* F03:C1263 (R1238) The function-name and each dummy-arg-name + shall be specified, explicitly or implicitly, to be scalar. */ + gfc_error ("Argument '%s' of statement function '%s' at %L " + "must be scalar", sym->name, proc->name, + &proc->declared_at); + continue; + } + + if (sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.u.cl; + if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + { + gfc_error ("Character-valued argument %qs of statement " + "function at %L must have constant length", + sym->name, &sym->declared_at); + continue; + } + } + } + } + formal_arg_flag = false; +} + + +/* 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 + || gfc_fl_struct (sym->attr.flavor) || sym->attr.intrinsic) + return; + + gfc_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); +} + + +static void +resolve_contained_fntype (gfc_symbol *sym, gfc_namespace *ns) +{ + bool t; + + if (sym && sym->attr.flavor == FL_PROCEDURE + && sym->ns->parent + && sym->ns->parent->proc_name + && sym->ns->parent->proc_name->attr.flavor == FL_PROCEDURE + && !strcmp (sym->name, sym->ns->parent->proc_name->name)) + gfc_error ("Contained procedure %qs at %L has the same name as its " + "encompassing procedure", sym->name, &sym->declared_at); + + /* If this namespace is not a function or an entry master function, + ignore it. */ + if (! sym || !(sym->attr.function || sym->attr.flavor == FL_VARIABLE) + || sym->attr.entry_master) + return; + + if (!sym->result) + return; + + /* Try to find out of what the return type is. */ + if (sym->result->ts.type == BT_UNKNOWN && sym->result->ts.interface == NULL) + { + t = gfc_set_default_type (sym->result, 0, ns); + + if (!t && !sym->result->attr.untyped) + { + if (sym->result == sym) + gfc_error ("Contained function %qs at %L has no IMPLICIT type", + sym->name, &sym->declared_at); + else if (!sym->result->attr.proc_pointer) + gfc_error ("Result %qs of contained function %qs at %L has " + "no IMPLICIT type", sym->result->name, sym->name, + &sym->result->declared_at); + sym->result->attr.untyped = 1; + } + } + + /* Fortran 2008 Draft Standard, page 535, C418, on type-param-value + type, lists the only ways a character length value of * can be used: + dummy arguments of procedures, named constants, function results and + in allocate statements if the allocate_object is an assumed length dummy + in external functions. Internal function results and results of module + procedures are not on this list, ergo, not permitted. */ + + if (sym->result->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->result->ts.u.cl; + if ((!cl || !cl->length) && !sym->result->ts.deferred) + { + /* See if this is a module-procedure and adapt error message + accordingly. */ + bool module_proc; + gcc_assert (ns->parent && ns->parent->proc_name); + module_proc = (ns->parent->proc_name->attr.flavor == FL_MODULE); + + gfc_error (module_proc + ? G_("Character-valued module procedure %qs at %L" + " must not be assumed length") + : G_("Character-valued internal function %qs at %L" + " must not be assumed length"), + sym->name, &sym->declared_at); + } + } +} + + +/* Add NEW_ARGS to the formal argument list of PROC, taking care not to + introduce duplicates. */ + +static void +merge_argument_lists (gfc_symbol *proc, gfc_formal_arglist *new_args) +{ + gfc_formal_arglist *f, *new_arglist; + gfc_symbol *new_sym; + + for (; new_args != NULL; new_args = new_args->next) + { + new_sym = new_args->sym; + /* See if this arg is already in the formal argument list. */ + for (f = proc->formal; f; f = f->next) + { + if (new_sym == f->sym) + break; + } + + if (f) + continue; + + /* Add a new argument. Argument order is not important. */ + new_arglist = gfc_get_formal_arglist (); + new_arglist->sym = new_sym; + new_arglist->next = proc->formal; + proc->formal = new_arglist; + } +} + + +/* Flag the arguments that are not present in all entries. */ + +static void +check_argument_lists (gfc_symbol *proc, gfc_formal_arglist *new_args) +{ + gfc_formal_arglist *f, *head; + head = new_args; + + for (f = proc->formal; f; f = f->next) + { + if (f->sym == NULL) + continue; + + for (new_args = head; new_args; new_args = new_args->next) + { + if (new_args->sym == f->sym) + break; + } + + if (new_args) + continue; + + f->sym->attr.not_always_present = 1; + } +} + + +/* Resolve alternate entry points. If a symbol has multiple entry points we + create a new master symbol for the main routine, and turn the existing + symbol into an entry point. */ + +static void +resolve_entries (gfc_namespace *ns) +{ + gfc_namespace *old_ns; + gfc_code *c; + gfc_symbol *proc; + gfc_entry_list *el; + char name[GFC_MAX_SYMBOL_LEN + 1]; + static int master_count = 0; + + if (ns->proc_name == NULL) + return; + + /* No need to do anything if this procedure doesn't have alternate entry + points. */ + if (!ns->entries) + return; + + /* We may already have resolved alternate entry points. */ + if (ns->proc_name->attr.entry_master) + return; + + /* If this isn't a procedure something has gone horribly wrong. */ + gcc_assert (ns->proc_name->attr.flavor == FL_PROCEDURE); + + /* Remember the current namespace. */ + old_ns = gfc_current_ns; + + gfc_current_ns = ns; + + /* Add the main entry point to the list of entry points. */ + el = gfc_get_entry_list (); + el->sym = ns->proc_name; + el->id = 0; + el->next = ns->entries; + ns->entries = el; + ns->proc_name->attr.entry = 1; + + /* If it is a module function, it needs to be in the right namespace + so that gfc_get_fake_result_decl can gather up the results. The + need for this arose in get_proc_name, where these beasts were + left in their own namespace, to keep prior references linked to + the entry declaration.*/ + if (ns->proc_name->attr.function + && ns->parent && ns->parent->proc_name->attr.flavor == FL_MODULE) + el->sym->ns = ns; + + /* Do the same for entries where the master is not a module + procedure. These are retained in the module namespace because + of the module procedure declaration. */ + for (el = el->next; el; el = el->next) + if (el->sym->ns->proc_name->attr.flavor == FL_MODULE + && el->sym->attr.mod_proc) + el->sym->ns = ns; + el = ns->entries; + + /* Add an entry statement for it. */ + c = gfc_get_code (EXEC_ENTRY); + c->ext.entry = el; + c->next = ns->code; + ns->code = c; + + /* Create a new symbol for the master function. */ + /* Give the internal function a unique name (within this file). + Also include the function name so the user has some hope of figuring + out what is going on. */ + snprintf (name, GFC_MAX_SYMBOL_LEN, "master.%d.%s", + master_count++, ns->proc_name->name); + gfc_get_ha_symbol (name, &proc); + gcc_assert (proc != NULL); + + gfc_add_procedure (&proc->attr, PROC_INTERNAL, proc->name, NULL); + if (ns->proc_name->attr.subroutine) + gfc_add_subroutine (&proc->attr, proc->name, NULL); + else + { + gfc_symbol *sym; + gfc_typespec *ts, *fts; + gfc_array_spec *as, *fas; + gfc_add_function (&proc->attr, proc->name, NULL); + proc->result = proc; + fas = ns->entries->sym->as; + fas = fas ? fas : ns->entries->sym->result->as; + fts = &ns->entries->sym->result->ts; + if (fts->type == BT_UNKNOWN) + fts = gfc_get_default_type (ns->entries->sym->result->name, NULL); + for (el = ns->entries->next; el; el = el->next) + { + ts = &el->sym->result->ts; + as = el->sym->as; + as = as ? as : el->sym->result->as; + if (ts->type == BT_UNKNOWN) + ts = gfc_get_default_type (el->sym->result->name, NULL); + + if (! gfc_compare_types (ts, fts) + || (el->sym->result->attr.dimension + != ns->entries->sym->result->attr.dimension) + || (el->sym->result->attr.pointer + != ns->entries->sym->result->attr.pointer)) + break; + else if (as && fas && ns->entries->sym->result != el->sym->result + && gfc_compare_array_spec (as, fas) == 0) + gfc_error ("Function %s at %L has entries with mismatched " + "array specifications", ns->entries->sym->name, + &ns->entries->sym->declared_at); + /* The characteristics need to match and thus both need to have + the same string length, i.e. both len=*, or both len=4. + Having both len=<variable> is also possible, but difficult to + check at compile time. */ + else if (ts->type == BT_CHARACTER + && (el->sym->result->attr.allocatable + != ns->entries->sym->result->attr.allocatable)) + { + gfc_error ("Function %s at %L has entry %s with mismatched " + "characteristics", ns->entries->sym->name, + &ns->entries->sym->declared_at, el->sym->name); + goto cleanup; + } + else if (ts->type == BT_CHARACTER && ts->u.cl && fts->u.cl + && (((ts->u.cl->length && !fts->u.cl->length) + ||(!ts->u.cl->length && fts->u.cl->length)) + || (ts->u.cl->length + && ts->u.cl->length->expr_type + != fts->u.cl->length->expr_type) + || (ts->u.cl->length + && ts->u.cl->length->expr_type == EXPR_CONSTANT + && mpz_cmp (ts->u.cl->length->value.integer, + fts->u.cl->length->value.integer) != 0))) + gfc_notify_std (GFC_STD_GNU, "Function %s at %L with " + "entries returning variables of different " + "string lengths", ns->entries->sym->name, + &ns->entries->sym->declared_at); + } + + if (el == NULL) + { + sym = ns->entries->sym->result; + /* All result types the same. */ + proc->ts = *fts; + if (sym->attr.dimension) + gfc_set_array_spec (proc, gfc_copy_array_spec (sym->as), NULL); + if (sym->attr.pointer) + gfc_add_pointer (&proc->attr, NULL); + } + else + { + /* Otherwise the result will be passed through a union by + reference. */ + proc->attr.mixed_entry_master = 1; + for (el = ns->entries; el; el = el->next) + { + sym = el->sym->result; + if (sym->attr.dimension) + { + if (el == ns->entries) + gfc_error ("FUNCTION result %s cannot be an array in " + "FUNCTION %s at %L", sym->name, + ns->entries->sym->name, &sym->declared_at); + else + gfc_error ("ENTRY result %s cannot be an array in " + "FUNCTION %s at %L", sym->name, + ns->entries->sym->name, &sym->declared_at); + } + else if (sym->attr.pointer) + { + if (el == ns->entries) + gfc_error ("FUNCTION result %s cannot be a POINTER in " + "FUNCTION %s at %L", sym->name, + ns->entries->sym->name, &sym->declared_at); + else + gfc_error ("ENTRY result %s cannot be a POINTER in " + "FUNCTION %s at %L", sym->name, + ns->entries->sym->name, &sym->declared_at); + } + else + { + ts = &sym->ts; + if (ts->type == BT_UNKNOWN) + ts = gfc_get_default_type (sym->name, NULL); + switch (ts->type) + { + case BT_INTEGER: + if (ts->kind == gfc_default_integer_kind) + sym = NULL; + break; + case BT_REAL: + if (ts->kind == gfc_default_real_kind + || ts->kind == gfc_default_double_kind) + sym = NULL; + break; + case BT_COMPLEX: + if (ts->kind == gfc_default_complex_kind) + sym = NULL; + break; + case BT_LOGICAL: + if (ts->kind == gfc_default_logical_kind) + sym = NULL; + break; + case BT_UNKNOWN: + /* We will issue error elsewhere. */ + sym = NULL; + break; + default: + break; + } + if (sym) + { + if (el == ns->entries) + gfc_error ("FUNCTION result %s cannot be of type %s " + "in FUNCTION %s at %L", sym->name, + gfc_typename (ts), ns->entries->sym->name, + &sym->declared_at); + else + gfc_error ("ENTRY result %s cannot be of type %s " + "in FUNCTION %s at %L", sym->name, + gfc_typename (ts), ns->entries->sym->name, + &sym->declared_at); + } + } + } + } + } + +cleanup: + proc->attr.access = ACCESS_PRIVATE; + proc->attr.entry_master = 1; + + /* Merge all the entry point arguments. */ + for (el = ns->entries; el; el = el->next) + merge_argument_lists (proc, el->sym->formal); + + /* Check the master formal arguments for any that are not + present in all entry points. */ + for (el = ns->entries; el; el = el->next) + check_argument_lists (proc, el->sym->formal); + + /* Use the master function for the function body. */ + ns->proc_name = proc; + + /* Finalize the new symbols. */ + gfc_commit_symbols (); + + /* Restore the original namespace. */ + gfc_current_ns = old_ns; +} + + +/* Resolve common variables. */ +static void +resolve_common_vars (gfc_common_head *common_block, bool named_common) +{ + gfc_symbol *csym = common_block->head; + gfc_gsymbol *gsym; + + for (; csym; csym = csym->common_next) + { + gsym = gfc_find_gsymbol (gfc_gsym_root, csym->name); + if (gsym && (gsym->type == GSYM_MODULE || gsym->type == GSYM_PROGRAM)) + gfc_error_now ("Global entity %qs at %L cannot appear in a " + "COMMON block at %L", gsym->name, + &gsym->where, &csym->common_block->where); + + /* gfc_add_in_common may have been called before, but the reported errors + have been ignored to continue parsing. + We do the checks again here. */ + if (!csym->attr.use_assoc) + { + gfc_add_in_common (&csym->attr, csym->name, &common_block->where); + gfc_notify_std (GFC_STD_F2018_OBS, "COMMON block at %L", + &common_block->where); + } + + if (csym->value || csym->attr.data) + { + if (!csym->ns->is_block_data) + gfc_notify_std (GFC_STD_GNU, "Variable %qs at %L is in COMMON " + "but only in BLOCK DATA initialization is " + "allowed", csym->name, &csym->declared_at); + else if (!named_common) + gfc_notify_std (GFC_STD_GNU, "Initialized variable %qs at %L is " + "in a blank COMMON but initialization is only " + "allowed in named common blocks", csym->name, + &csym->declared_at); + } + + if (UNLIMITED_POLY (csym)) + gfc_error_now ("%qs at %L cannot appear in COMMON " + "[F2008:C5100]", csym->name, &csym->declared_at); + + if (csym->ts.type != BT_DERIVED) + continue; + + if (!(csym->ts.u.derived->attr.sequence + || csym->ts.u.derived->attr.is_bind_c)) + gfc_error_now ("Derived type variable %qs in COMMON at %L " + "has neither the SEQUENCE nor the BIND(C) " + "attribute", csym->name, &csym->declared_at); + if (csym->ts.u.derived->attr.alloc_comp) + gfc_error_now ("Derived type variable %qs in COMMON at %L " + "has an ultimate component that is " + "allocatable", csym->name, &csym->declared_at); + if (gfc_has_default_initializer (csym->ts.u.derived)) + gfc_error_now ("Derived type variable %qs in COMMON at %L " + "may not have default initializer", csym->name, + &csym->declared_at); + + if (csym->attr.flavor == FL_UNKNOWN && !csym->attr.proc_pointer) + gfc_add_flavor (&csym->attr, FL_VARIABLE, csym->name, &csym->declared_at); + } +} + +/* Resolve common blocks. */ +static void +resolve_common_blocks (gfc_symtree *common_root) +{ + gfc_symbol *sym; + gfc_gsymbol * gsym; + + if (common_root == NULL) + return; + + if (common_root->left) + resolve_common_blocks (common_root->left); + if (common_root->right) + resolve_common_blocks (common_root->right); + + resolve_common_vars (common_root->n.common, true); + + /* The common name is a global name - in Fortran 2003 also if it has a + C binding name, since Fortran 2008 only the C binding name is a global + identifier. */ + if (!common_root->n.common->binding_label + || gfc_notification_std (GFC_STD_F2008)) + { + gsym = gfc_find_gsymbol (gfc_gsym_root, + common_root->n.common->name); + + if (gsym && gfc_notification_std (GFC_STD_F2008) + && gsym->type == GSYM_COMMON + && ((common_root->n.common->binding_label + && (!gsym->binding_label + || strcmp (common_root->n.common->binding_label, + gsym->binding_label) != 0)) + || (!common_root->n.common->binding_label + && gsym->binding_label))) + { + gfc_error ("In Fortran 2003 COMMON %qs block at %L is a global " + "identifier and must thus have the same binding name " + "as the same-named COMMON block at %L: %s vs %s", + common_root->n.common->name, &common_root->n.common->where, + &gsym->where, + common_root->n.common->binding_label + ? common_root->n.common->binding_label : "(blank)", + gsym->binding_label ? gsym->binding_label : "(blank)"); + return; + } + + if (gsym && gsym->type != GSYM_COMMON + && !common_root->n.common->binding_label) + { + gfc_error ("COMMON block %qs at %L uses the same global identifier " + "as entity at %L", + common_root->n.common->name, &common_root->n.common->where, + &gsym->where); + return; + } + if (gsym && gsym->type != GSYM_COMMON) + { + gfc_error ("Fortran 2008: COMMON block %qs with binding label at " + "%L sharing the identifier with global non-COMMON-block " + "entity at %L", common_root->n.common->name, + &common_root->n.common->where, &gsym->where); + return; + } + if (!gsym) + { + gsym = gfc_get_gsymbol (common_root->n.common->name, false); + gsym->type = GSYM_COMMON; + gsym->where = common_root->n.common->where; + gsym->defined = 1; + } + gsym->used = 1; + } + + if (common_root->n.common->binding_label) + { + gsym = gfc_find_gsymbol (gfc_gsym_root, + common_root->n.common->binding_label); + if (gsym && gsym->type != GSYM_COMMON) + { + gfc_error ("COMMON block at %L with binding label %qs uses the same " + "global identifier as entity at %L", + &common_root->n.common->where, + common_root->n.common->binding_label, &gsym->where); + return; + } + if (!gsym) + { + gsym = gfc_get_gsymbol (common_root->n.common->binding_label, true); + gsym->type = GSYM_COMMON; + gsym->where = common_root->n.common->where; + gsym->defined = 1; + } + gsym->used = 1; + } + + gfc_find_symbol (common_root->name, gfc_current_ns, 0, &sym); + if (sym == NULL) + return; + + if (sym->attr.flavor == FL_PARAMETER) + gfc_error ("COMMON block %qs at %L is used as PARAMETER at %L", + sym->name, &common_root->n.common->where, &sym->declared_at); + + if (sym->attr.external) + gfc_error ("COMMON block %qs at %L cannot have the EXTERNAL attribute", + sym->name, &common_root->n.common->where); + + if (sym->attr.intrinsic) + gfc_error ("COMMON block %qs at %L is also an intrinsic procedure", + sym->name, &common_root->n.common->where); + else if (sym->attr.result + || gfc_is_function_return_value (sym, gfc_current_ns)) + gfc_notify_std (GFC_STD_F2003, "COMMON block %qs at %L " + "that is also a function result", sym->name, + &common_root->n.common->where); + else if (sym->attr.flavor == FL_PROCEDURE && sym->attr.proc != PROC_INTERNAL + && sym->attr.proc != PROC_ST_FUNCTION) + gfc_notify_std (GFC_STD_F2003, "COMMON block %qs at %L " + "that is also a global procedure", sym->name, + &common_root->n.common->where); +} + + +/* 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_namespace *child; + gfc_entry_list *el; + + resolve_formal_arglists (ns); + + for (child = ns->contained; child; child = child->sibling) + { + /* Resolve alternate entry points first. */ + resolve_entries (child); + + /* Then check function return types. */ + resolve_contained_fntype (child->proc_name, child); + for (el = child->entries; el; el = el->next) + resolve_contained_fntype (el->sym, child); + } +} + + + +/* A Parameterized Derived Type constructor must contain values for + the PDT KIND parameters or they must have a default initializer. + Go through the constructor picking out the KIND expressions, + storing them in 'param_list' and then call gfc_get_pdt_instance + to obtain the PDT instance. */ + +static gfc_actual_arglist *param_list, *param_tail, *param; + +static bool +get_pdt_spec_expr (gfc_component *c, gfc_expr *expr) +{ + param = gfc_get_actual_arglist (); + if (!param_list) + param_list = param_tail = param; + else + { + param_tail->next = param; + param_tail = param_tail->next; + } + + param_tail->name = c->name; + if (expr) + param_tail->expr = gfc_copy_expr (expr); + else if (c->initializer) + param_tail->expr = gfc_copy_expr (c->initializer); + else + { + param_tail->spec_type = SPEC_ASSUMED; + if (c->attr.pdt_kind) + { + gfc_error ("The KIND parameter %qs in the PDT constructor " + "at %C has no value", param->name); + return false; + } + } + + return true; +} + +static bool +get_pdt_constructor (gfc_expr *expr, gfc_constructor **constr, + gfc_symbol *derived) +{ + gfc_constructor *cons = NULL; + gfc_component *comp; + bool t = true; + + if (expr && expr->expr_type == EXPR_STRUCTURE) + cons = gfc_constructor_first (expr->value.constructor); + else if (constr) + cons = *constr; + gcc_assert (cons); + + comp = derived->components; + + for (; comp && cons; comp = comp->next, cons = gfc_constructor_next (cons)) + { + if (cons->expr + && cons->expr->expr_type == EXPR_STRUCTURE + && comp->ts.type == BT_DERIVED) + { + t = get_pdt_constructor (cons->expr, NULL, comp->ts.u.derived); + if (!t) + return t; + } + else if (comp->ts.type == BT_DERIVED) + { + t = get_pdt_constructor (NULL, &cons, comp->ts.u.derived); + if (!t) + return t; + } + else if ((comp->attr.pdt_kind || comp->attr.pdt_len) + && derived->attr.pdt_template) + { + t = get_pdt_spec_expr (comp, cons->expr); + if (!t) + return t; + } + } + return t; +} + + +static bool resolve_fl_derived0 (gfc_symbol *sym); +static bool resolve_fl_struct (gfc_symbol *sym); + + +/* Resolve all of the elements of a structure constructor and make sure that + the types are correct. The 'init' flag indicates that the given + constructor is an initializer. */ + +static bool +resolve_structure_cons (gfc_expr *expr, int init) +{ + gfc_constructor *cons; + gfc_component *comp; + bool t; + symbol_attribute a; + + t = true; + + if (expr->ts.type == BT_DERIVED || expr->ts.type == BT_UNION) + { + if (expr->ts.u.derived->attr.flavor == FL_DERIVED) + resolve_fl_derived0 (expr->ts.u.derived); + else + resolve_fl_struct (expr->ts.u.derived); + + /* If this is a Parameterized Derived Type template, find the + instance corresponding to the PDT kind parameters. */ + if (expr->ts.u.derived->attr.pdt_template) + { + param_list = NULL; + t = get_pdt_constructor (expr, NULL, expr->ts.u.derived); + if (!t) + return t; + gfc_get_pdt_instance (param_list, &expr->ts.u.derived, NULL); + + expr->param_list = gfc_copy_actual_arglist (param_list); + + if (param_list) + gfc_free_actual_arglist (param_list); + + if (!expr->ts.u.derived->attr.pdt_type) + return false; + } + } + + cons = gfc_constructor_first (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.u.derived->components; + + for (; comp && cons; comp = comp->next, cons = gfc_constructor_next (cons)) + { + int rank; + + if (!cons->expr) + continue; + + /* Unions use an EXPR_NULL contrived expression to tell the translation + phase to generate an initializer of the appropriate length. + Ignore it here. */ + if (cons->expr->ts.type == BT_UNION && cons->expr->expr_type == EXPR_NULL) + continue; + + if (!gfc_resolve_expr (cons->expr)) + { + t = false; + continue; + } + + rank = comp->as ? comp->as->rank : 0; + if (comp->ts.type == BT_CLASS + && !comp->ts.u.derived->attr.unlimited_polymorphic + && CLASS_DATA (comp)->as) + rank = CLASS_DATA (comp)->as->rank; + + if (cons->expr->expr_type != EXPR_NULL && rank != cons->expr->rank + && (comp->attr.allocatable || cons->expr->rank)) + { + gfc_error ("The rank of the element in the structure " + "constructor at %L does not match that of the " + "component (%d/%d)", &cons->expr->where, + cons->expr->rank, rank); + t = false; + } + + /* If we don't have the right type, try to convert it. */ + + if (!comp->attr.proc_pointer && + !gfc_compare_types (&cons->expr->ts, &comp->ts)) + { + if (strcmp (comp->name, "_extends") == 0) + { + /* Can afford to be brutal with the _extends initializer. + The derived type can get lost because it is PRIVATE + but it is not usage constrained by the standard. */ + cons->expr->ts = comp->ts; + } + else if (comp->attr.pointer && cons->expr->ts.type != BT_UNKNOWN) + { + gfc_error ("The element in the structure constructor at %L, " + "for pointer component %qs, is %s but should be %s", + &cons->expr->where, comp->name, + gfc_basic_typename (cons->expr->ts.type), + gfc_basic_typename (comp->ts.type)); + t = false; + } + else + { + bool t2 = gfc_convert_type (cons->expr, &comp->ts, 1); + if (t) + t = t2; + } + } + + /* For strings, the length of the constructor should be the same as + the one of the structure, ensure this if the lengths are known at + compile time and when we are dealing with PARAMETER or structure + constructors. */ + if (cons->expr->ts.type == BT_CHARACTER && comp->ts.u.cl + && comp->ts.u.cl->length + && comp->ts.u.cl->length->expr_type == EXPR_CONSTANT + && cons->expr->ts.u.cl && cons->expr->ts.u.cl->length + && cons->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT + && cons->expr->rank != 0 + && mpz_cmp (cons->expr->ts.u.cl->length->value.integer, + comp->ts.u.cl->length->value.integer) != 0) + { + if (cons->expr->expr_type == EXPR_VARIABLE + && cons->expr->symtree->n.sym->attr.flavor == FL_PARAMETER) + { + /* Wrap the parameter in an array constructor (EXPR_ARRAY) + to make use of the gfc_resolve_character_array_constructor + machinery. The expression is later simplified away to + an array of string literals. */ + gfc_expr *para = cons->expr; + cons->expr = gfc_get_expr (); + cons->expr->ts = para->ts; + cons->expr->where = para->where; + cons->expr->expr_type = EXPR_ARRAY; + cons->expr->rank = para->rank; + cons->expr->shape = gfc_copy_shape (para->shape, para->rank); + gfc_constructor_append_expr (&cons->expr->value.constructor, + para, &cons->expr->where); + } + + if (cons->expr->expr_type == EXPR_ARRAY) + { + /* Rely on the cleanup of the namespace to deal correctly with + the old charlen. (There was a block here that attempted to + remove the charlen but broke the chain in so doing.) */ + cons->expr->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL); + cons->expr->ts.u.cl->length_from_typespec = true; + cons->expr->ts.u.cl->length = gfc_copy_expr (comp->ts.u.cl->length); + gfc_resolve_character_array_constructor (cons->expr); + } + } + + if (cons->expr->expr_type == EXPR_NULL + && !(comp->attr.pointer || comp->attr.allocatable + || comp->attr.proc_pointer || comp->ts.f90_type == BT_VOID + || (comp->ts.type == BT_CLASS + && (CLASS_DATA (comp)->attr.class_pointer + || CLASS_DATA (comp)->attr.allocatable)))) + { + t = false; + gfc_error ("The NULL in the structure constructor at %L is " + "being applied to component %qs, which is neither " + "a POINTER nor ALLOCATABLE", &cons->expr->where, + comp->name); + } + + if (comp->attr.proc_pointer && comp->ts.interface) + { + /* Check procedure pointer interface. */ + gfc_symbol *s2 = NULL; + gfc_component *c2; + const char *name; + char err[200]; + + c2 = gfc_get_proc_ptr_comp (cons->expr); + if (c2) + { + s2 = c2->ts.interface; + name = c2->name; + } + else if (cons->expr->expr_type == EXPR_FUNCTION) + { + s2 = cons->expr->symtree->n.sym->result; + name = cons->expr->symtree->n.sym->result->name; + } + else if (cons->expr->expr_type != EXPR_NULL) + { + s2 = cons->expr->symtree->n.sym; + name = cons->expr->symtree->n.sym->name; + } + + if (s2 && !gfc_compare_interfaces (comp->ts.interface, s2, name, 0, 1, + err, sizeof (err), NULL, NULL)) + { + gfc_error_opt (0, "Interface mismatch for procedure-pointer " + "component %qs in structure constructor at %L:" + " %s", comp->name, &cons->expr->where, err); + return false; + } + } + + /* Validate shape, except for dynamic or PDT arrays. */ + if (cons->expr->expr_type == EXPR_ARRAY && rank == cons->expr->rank + && comp->as && !comp->attr.allocatable && !comp->attr.pointer + && !comp->attr.pdt_array) + { + mpz_t len; + mpz_init (len); + for (int n = 0; n < rank; n++) + { + if (comp->as->upper[n]->expr_type != EXPR_CONSTANT + || comp->as->lower[n]->expr_type != EXPR_CONSTANT) + { + gfc_error ("Bad array spec of component %qs referenced in " + "structure constructor at %L", + comp->name, &cons->expr->where); + t = false; + break; + }; + mpz_set_ui (len, 1); + mpz_add (len, len, comp->as->upper[n]->value.integer); + mpz_sub (len, len, comp->as->lower[n]->value.integer); + if (mpz_cmp (cons->expr->shape[n], len) != 0) + { + gfc_error ("The shape of component %qs in the structure " + "constructor at %L differs from the shape of the " + "declared component for dimension %d (%ld/%ld)", + comp->name, &cons->expr->where, n+1, + mpz_get_si (cons->expr->shape[n]), + mpz_get_si (len)); + t = false; + } + } + mpz_clear (len); + } + + if (!comp->attr.pointer || comp->attr.proc_pointer + || cons->expr->expr_type == EXPR_NULL) + continue; + + a = gfc_expr_attr (cons->expr); + + if (!a.pointer && !a.target) + { + t = false; + gfc_error ("The element in the structure constructor at %L, " + "for pointer component %qs should be a POINTER or " + "a TARGET", &cons->expr->where, comp->name); + } + + if (init) + { + /* F08:C461. Additional checks for pointer initialization. */ + if (a.allocatable) + { + t = false; + gfc_error ("Pointer initialization target at %L " + "must not be ALLOCATABLE", &cons->expr->where); + } + if (!a.save) + { + t = false; + gfc_error ("Pointer initialization target at %L " + "must have the SAVE attribute", &cons->expr->where); + } + } + + /* F2003, C1272 (3). */ + bool impure = cons->expr->expr_type == EXPR_VARIABLE + && (gfc_impure_variable (cons->expr->symtree->n.sym) + || gfc_is_coindexed (cons->expr)); + if (impure && gfc_pure (NULL)) + { + t = false; + gfc_error ("Invalid expression in the structure constructor for " + "pointer component %qs at %L in PURE procedure", + comp->name, &cons->expr->where); + } + + if (impure) + gfc_unset_implicit_pure (NULL); + } + + return t; +} + + +/****************** Expression name resolution ******************/ + +/* Returns 0 if a symbol was not declared with a type 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.dummy || a.external || a.intrinsic + || a.optional || a.pointer || a.save || a.target || a.volatile_ + || a.value || a.access != ACCESS_UNKNOWN || a.intent != INTENT_UNKNOWN + || a.asynchronous || a.codimension) + 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); + + if (s != NULL) + { + if (s == sym) + return 0; + else + return generic_sym (s); + } + + return 0; +} + + +/* 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. */ + +enum proc_type +{ PTYPE_GENERIC = 1, PTYPE_SPECIFIC, PTYPE_UNKNOWN }; + +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; +} + +/* Check references to assumed size arrays. The flag need_full_assumed_size + is nonzero when matching actual arguments. */ + +static int need_full_assumed_size = 0; + +static bool +check_assumed_size_reference (gfc_symbol *sym, gfc_expr *e) +{ + if (need_full_assumed_size || !(sym->as && sym->as->type == AS_ASSUMED_SIZE)) + return false; + + /* FIXME: The comparison "e->ref->u.ar.type == AR_FULL" is wrong. + What should it be? */ + if (e->ref && (e->ref->u.ar.end[e->ref->u.ar.as->rank - 1] == NULL) + && (e->ref->u.ar.as->type == AS_ASSUMED_SIZE) + && (e->ref->u.ar.type == AR_FULL)) + { + gfc_error ("The upper bound in the last dimension must " + "appear in the reference to the assumed size " + "array %qs at %L", sym->name, &e->where); + return true; + } + return false; +} + + +/* Look for bad assumed size array references in argument expressions + of elemental and array valued intrinsic procedures. Since this is + called from procedure resolution functions, it only recurses at + operators. */ + +static bool +resolve_assumed_size_actual (gfc_expr *e) +{ + if (e == NULL) + return false; + + switch (e->expr_type) + { + case EXPR_VARIABLE: + if (e->symtree && check_assumed_size_reference (e->symtree->n.sym, e)) + return true; + break; + + case EXPR_OP: + if (resolve_assumed_size_actual (e->value.op.op1) + || resolve_assumed_size_actual (e->value.op.op2)) + return true; + break; + + default: + break; + } + return false; +} + + +/* Check a generic procedure, passed as an actual argument, to see if + there is a matching specific name. If none, it is an error, and if + more than one, the reference is ambiguous. */ +static int +count_specific_procs (gfc_expr *e) +{ + int n; + gfc_interface *p; + gfc_symbol *sym; + + n = 0; + sym = e->symtree->n.sym; + + for (p = sym->generic; p; p = p->next) + if (strcmp (sym->name, p->sym->name) == 0) + { + e->symtree = gfc_find_symtree (p->sym->ns->sym_root, + sym->name); + n++; + } + + if (n > 1) + gfc_error ("%qs at %L is ambiguous", e->symtree->n.sym->name, + &e->where); + + if (n == 0) + gfc_error ("GENERIC procedure %qs is not allowed as an actual " + "argument at %L", sym->name, &e->where); + + return n; +} + + +/* See if a call to sym could possibly be a not allowed RECURSION because of + a missing RECURSIVE declaration. This means that either sym is the current + context itself, or sym is the parent of a contained procedure calling its + non-RECURSIVE containing procedure. + This also works if sym is an ENTRY. */ + +static bool +is_illegal_recursion (gfc_symbol* sym, gfc_namespace* context) +{ + gfc_symbol* proc_sym; + gfc_symbol* context_proc; + gfc_namespace* real_context; + + if (sym->attr.flavor == FL_PROGRAM + || gfc_fl_struct (sym->attr.flavor)) + return false; + + /* If we've got an ENTRY, find real procedure. */ + if (sym->attr.entry && sym->ns->entries) + proc_sym = sym->ns->entries->sym; + else + proc_sym = sym; + + /* If sym is RECURSIVE, all is well of course. */ + if (proc_sym->attr.recursive || flag_recursive) + return false; + + /* Find the context procedure's "real" symbol if it has entries. + We look for a procedure symbol, so recurse on the parents if we don't + find one (like in case of a BLOCK construct). */ + for (real_context = context; ; real_context = real_context->parent) + { + /* We should find something, eventually! */ + gcc_assert (real_context); + + context_proc = (real_context->entries ? real_context->entries->sym + : real_context->proc_name); + + /* In some special cases, there may not be a proc_name, like for this + invalid code: + real(bad_kind()) function foo () ... + when checking the call to bad_kind (). + In these cases, we simply return here and assume that the + call is ok. */ + if (!context_proc) + return false; + + if (context_proc->attr.flavor != FL_LABEL) + break; + } + + /* A call from sym's body to itself is recursion, of course. */ + if (context_proc == proc_sym) + return true; + + /* The same is true if context is a contained procedure and sym the + containing one. */ + if (context_proc->attr.contained) + { + gfc_symbol* parent_proc; + + gcc_assert (context->parent); + parent_proc = (context->parent->entries ? context->parent->entries->sym + : context->parent->proc_name); + + if (parent_proc == proc_sym) + return true; + } + + return false; +} + + +/* Resolve an intrinsic procedure: Set its function/subroutine attribute, + its typespec and formal argument list. */ + +bool +gfc_resolve_intrinsic (gfc_symbol *sym, locus *loc) +{ + gfc_intrinsic_sym* isym = NULL; + const char* symstd; + + if (sym->resolve_symbol_called >= 2) + return true; + + sym->resolve_symbol_called = 2; + + /* Already resolved. */ + if (sym->from_intmod && sym->ts.type != BT_UNKNOWN) + return true; + + /* We already know this one is an intrinsic, so we don't call + gfc_is_intrinsic for full checking but rather use gfc_find_function and + gfc_find_subroutine directly to check whether it is a function or + subroutine. */ + + if (sym->intmod_sym_id && sym->attr.subroutine) + { + gfc_isym_id id = gfc_isym_id_by_intmod_sym (sym); + isym = gfc_intrinsic_subroutine_by_id (id); + } + else if (sym->intmod_sym_id) + { + gfc_isym_id id = gfc_isym_id_by_intmod_sym (sym); + isym = gfc_intrinsic_function_by_id (id); + } + else if (!sym->attr.subroutine) + isym = gfc_find_function (sym->name); + + if (isym && !sym->attr.subroutine) + { + if (sym->ts.type != BT_UNKNOWN && warn_surprising + && !sym->attr.implicit_type) + gfc_warning (OPT_Wsurprising, + "Type specified for intrinsic function %qs at %L is" + " ignored", sym->name, &sym->declared_at); + + if (!sym->attr.function && + !gfc_add_function(&sym->attr, sym->name, loc)) + return false; + + sym->ts = isym->ts; + } + else if (isym || (isym = gfc_find_subroutine (sym->name))) + { + if (sym->ts.type != BT_UNKNOWN && !sym->attr.implicit_type) + { + gfc_error ("Intrinsic subroutine %qs at %L shall not have a type" + " specifier", sym->name, &sym->declared_at); + return false; + } + + if (!sym->attr.subroutine && + !gfc_add_subroutine(&sym->attr, sym->name, loc)) + return false; + } + else + { + gfc_error ("%qs declared INTRINSIC at %L does not exist", sym->name, + &sym->declared_at); + return false; + } + + gfc_copy_formal_args_intr (sym, isym, NULL); + + sym->attr.pure = isym->pure; + sym->attr.elemental = isym->elemental; + + /* Check it is actually available in the standard settings. */ + if (!gfc_check_intrinsic_standard (isym, &symstd, false, sym->declared_at)) + { + gfc_error ("The intrinsic %qs declared INTRINSIC at %L is not " + "available in the current standard settings but %s. Use " + "an appropriate %<-std=*%> option or enable " + "%<-fall-intrinsics%> in order to use it.", + sym->name, &sym->declared_at, symstd); + return false; + } + + return true; +} + + +/* Resolve a procedure expression, like passing it to a called procedure or as + RHS for a procedure pointer assignment. */ + +static bool +resolve_procedure_expression (gfc_expr* expr) +{ + gfc_symbol* sym; + + if (expr->expr_type != EXPR_VARIABLE) + return true; + gcc_assert (expr->symtree); + + sym = expr->symtree->n.sym; + + if (sym->attr.intrinsic) + gfc_resolve_intrinsic (sym, &expr->where); + + if (sym->attr.flavor != FL_PROCEDURE + || (sym->attr.function && sym->result == sym)) + return true; + + /* A non-RECURSIVE procedure that is used as procedure expression within its + own body is in danger of being called recursively. */ + if (is_illegal_recursion (sym, gfc_current_ns)) + gfc_warning (0, "Non-RECURSIVE procedure %qs at %L is possibly calling" + " itself recursively. Declare it RECURSIVE or use" + " %<-frecursive%>", sym->name, &expr->where); + + return true; +} + + +/* Check that name is not a derived type. */ + +static bool +is_dt_name (const char *name) +{ + gfc_symbol *dt_list, *dt_first; + + dt_list = dt_first = gfc_derived_types; + for (; dt_list; dt_list = dt_list->dt_next) + { + if (strcmp(dt_list->name, name) == 0) + return true; + if (dt_first == dt_list->dt_next) + break; + } + return false; +} + + +/* 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 bool +resolve_actual_arglist (gfc_actual_arglist *arg, procedure_type ptype, + bool no_formal_args) +{ + gfc_symbol *sym; + gfc_symtree *parent_st; + gfc_expr *e; + gfc_component *comp; + int save_need_full_assumed_size; + bool return_value = false; + bool actual_arg_sav = actual_arg, first_actual_arg_sav = first_actual_arg; + + actual_arg = true; + first_actual_arg = true; + + 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); + goto cleanup; + } + } + first_actual_arg = false; + continue; + } + + if (e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.generic + && no_formal_args + && count_specific_procs (e) != 1) + goto cleanup; + + if (e->ts.type != BT_PROCEDURE) + { + save_need_full_assumed_size = need_full_assumed_size; + if (e->expr_type != EXPR_VARIABLE) + need_full_assumed_size = 0; + if (!gfc_resolve_expr (e)) + goto cleanup; + need_full_assumed_size = save_need_full_assumed_size; + goto argument_list; + } + + /* See if the expression node should really be a variable reference. */ + + sym = e->symtree->n.sym; + + if (sym->attr.flavor == FL_PROCEDURE && is_dt_name (sym->name)) + { + gfc_error ("Derived type %qs is used as an actual " + "argument at %L", sym->name, &e->where); + goto cleanup; + } + + if (sym->attr.flavor == FL_PROCEDURE + || sym->attr.intrinsic + || sym->attr.external) + { + int actual_ok; + + /* If a procedure is not already determined to be something else + check if it is intrinsic. */ + if (gfc_is_intrinsic (sym, sym->attr.subroutine, e->where)) + sym->attr.intrinsic = 1; + + if (sym->attr.proc == PROC_ST_FUNCTION) + { + gfc_error ("Statement function %qs at %L is not allowed as an " + "actual argument", sym->name, &e->where); + } + + actual_ok = gfc_intrinsic_actual_ok (sym->name, + sym->attr.subroutine); + if (sym->attr.intrinsic && actual_ok == 0) + { + gfc_error ("Intrinsic %qs at %L is not allowed as an " + "actual argument", sym->name, &e->where); + } + + if (sym->attr.contained && !sym->attr.use_assoc + && sym->ns->proc_name->attr.flavor != FL_MODULE) + { + if (!gfc_notify_std (GFC_STD_F2008, "Internal procedure %qs is" + " used as actual argument at %L", + sym->name, &e->where)) + goto cleanup; + } + + if (sym->attr.elemental && !sym->attr.intrinsic) + { + gfc_error ("ELEMENTAL non-INTRINSIC procedure %qs is not " + "allowed as an actual argument at %L", sym->name, + &e->where); + } + + /* Check if a generic interface has a specific procedure + with the same name before emitting an error. */ + if (sym->attr.generic && count_specific_procs (e) != 1) + goto cleanup; + + /* Just in case a specific was found for the expression. */ + sym = e->symtree->n.sym; + + /* If the symbol is the function that names the current (or + parent) scope, then we really have a variable reference. */ + + if (gfc_is_function_return_value (sym, sym->ns)) + goto got_variable; + + /* If all else fails, see if we have a specific intrinsic. */ + if (sym->ts.type == BT_UNKNOWN && sym->attr.intrinsic) + { + gfc_intrinsic_sym *isym; + + isym = gfc_find_function (sym->name); + if (isym == NULL || !isym->specific) + { + gfc_error ("Unable to find a specific INTRINSIC procedure " + "for the reference %qs at %L", sym->name, + &e->where); + goto cleanup; + } + sym->ts = isym->ts; + sym->attr.intrinsic = 1; + sym->attr.function = 1; + } + + if (!gfc_resolve_expr (e)) + goto cleanup; + goto argument_list; + } + + /* 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 %qs at %L is ambiguous", sym->name, &e->where); + goto cleanup; + } + + 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) + { + if (!gfc_resolve_expr (e)) + goto cleanup; + goto argument_list; + } + + got_variable: + e->expr_type = EXPR_VARIABLE; + e->ts = sym->ts; + if ((sym->as != NULL && sym->ts.type != BT_CLASS) + || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && CLASS_DATA (sym)->as)) + { + e->rank = sym->ts.type == BT_CLASS + ? CLASS_DATA (sym)->as->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->ts.type == BT_CLASS + ? CLASS_DATA (sym)->as : sym->as; + } + + /* Expressions are assigned a default ts.type of BT_PROCEDURE in + primary.c (match_actual_arg). If above code determines that it + is a variable instead, it needs to be resolved as it was not + done at the beginning of this function. */ + save_need_full_assumed_size = need_full_assumed_size; + if (e->expr_type != EXPR_VARIABLE) + need_full_assumed_size = 0; + if (!gfc_resolve_expr (e)) + goto cleanup; + need_full_assumed_size = save_need_full_assumed_size; + + argument_list: + /* Check argument list functions %VAL, %LOC and %REF. There is + nothing to do for %REF. */ + if (arg->name && arg->name[0] == '%') + { + if (strcmp ("%VAL", arg->name) == 0) + { + if (e->ts.type == BT_CHARACTER || e->ts.type == BT_DERIVED) + { + gfc_error ("By-value argument at %L is not of numeric " + "type", &e->where); + goto cleanup; + } + + if (e->rank) + { + gfc_error ("By-value argument at %L cannot be an array or " + "an array section", &e->where); + goto cleanup; + } + + /* Intrinsics are still PROC_UNKNOWN here. However, + since same file external procedures are not resolvable + in gfortran, it is a good deal easier to leave them to + intrinsic.c. */ + if (ptype != PROC_UNKNOWN + && ptype != PROC_DUMMY + && ptype != PROC_EXTERNAL + && ptype != PROC_MODULE) + { + gfc_error ("By-value argument at %L is not allowed " + "in this context", &e->where); + goto cleanup; + } + } + + /* Statement functions have already been excluded above. */ + else if (strcmp ("%LOC", arg->name) == 0 + && e->ts.type == BT_PROCEDURE) + { + if (e->symtree->n.sym->attr.proc == PROC_INTERNAL) + { + gfc_error ("Passing internal procedure at %L by location " + "not allowed", &e->where); + goto cleanup; + } + } + } + + comp = gfc_get_proc_ptr_comp(e); + if (e->expr_type == EXPR_VARIABLE + && comp && comp->attr.elemental) + { + gfc_error ("ELEMENTAL procedure pointer component %qs is not " + "allowed as an actual argument at %L", comp->name, + &e->where); + } + + /* Fortran 2008, C1237. */ + if (e->expr_type == EXPR_VARIABLE && gfc_is_coindexed (e) + && gfc_has_ultimate_pointer (e)) + { + gfc_error ("Coindexed actual argument at %L with ultimate pointer " + "component", &e->where); + goto cleanup; + } + + first_actual_arg = false; + } + + return_value = true; + +cleanup: + actual_arg = actual_arg_sav; + first_actual_arg = first_actual_arg_sav; + + return return_value; +} + + +/* Do the checks of the actual argument list that are specific to elemental + procedures. If called with c == NULL, we have a function, otherwise if + expr == NULL, we have a subroutine. */ + +static bool +resolve_elemental_actual (gfc_expr *expr, gfc_code *c) +{ + gfc_actual_arglist *arg0; + gfc_actual_arglist *arg; + gfc_symbol *esym = NULL; + gfc_intrinsic_sym *isym = NULL; + gfc_expr *e = NULL; + gfc_intrinsic_arg *iformal = NULL; + gfc_formal_arglist *eformal = NULL; + bool formal_optional = false; + bool set_by_optional = false; + int i; + int rank = 0; + + /* Is this an elemental procedure? */ + if (expr && expr->value.function.actual != NULL) + { + if (expr->value.function.esym != NULL + && expr->value.function.esym->attr.elemental) + { + arg0 = expr->value.function.actual; + esym = expr->value.function.esym; + } + else if (expr->value.function.isym != NULL + && expr->value.function.isym->elemental) + { + arg0 = expr->value.function.actual; + isym = expr->value.function.isym; + } + else + return true; + } + else if (c && c->ext.actual != NULL) + { + arg0 = c->ext.actual; + + if (c->resolved_sym) + esym = c->resolved_sym; + else + esym = c->symtree->n.sym; + gcc_assert (esym); + + if (!esym->attr.elemental) + return true; + } + else + return true; + + /* The rank of an elemental is the rank of its array argument(s). */ + for (arg = arg0; arg; arg = arg->next) + { + if (arg->expr != NULL && arg->expr->rank != 0) + { + rank = arg->expr->rank; + if (arg->expr->expr_type == EXPR_VARIABLE + && arg->expr->symtree->n.sym->attr.optional) + set_by_optional = true; + + /* Function specific; set the result rank and shape. */ + if (expr) + { + expr->rank = rank; + if (!expr->shape && arg->expr->shape) + { + expr->shape = gfc_get_shape (rank); + for (i = 0; i < rank; i++) + mpz_init_set (expr->shape[i], arg->expr->shape[i]); + } + } + break; + } + } + + /* If it is an array, it shall not be supplied as an actual argument + to an elemental procedure unless an array of the same rank is supplied + as an actual argument corresponding to a nonoptional dummy argument of + that elemental procedure(12.4.1.5). */ + formal_optional = false; + if (isym) + iformal = isym->formal; + else + eformal = esym->formal; + + for (arg = arg0; arg; arg = arg->next) + { + if (eformal) + { + if (eformal->sym && eformal->sym->attr.optional) + formal_optional = true; + eformal = eformal->next; + } + else if (isym && iformal) + { + if (iformal->optional) + formal_optional = true; + iformal = iformal->next; + } + else if (isym) + formal_optional = true; + + if (pedantic && arg->expr != NULL + && arg->expr->expr_type == EXPR_VARIABLE + && arg->expr->symtree->n.sym->attr.optional + && formal_optional + && arg->expr->rank + && (set_by_optional || arg->expr->rank != rank) + && !(isym && isym->id == GFC_ISYM_CONVERSION)) + { + bool t = false; + gfc_actual_arglist *a; + + /* Scan the argument list for a non-optional argument with the + same rank as arg. */ + for (a = arg0; a; a = a->next) + if (a != arg + && a->expr->rank == arg->expr->rank + && !a->expr->symtree->n.sym->attr.optional) + { + t = true; + break; + } + + if (!t) + gfc_warning (OPT_Wpedantic, + "%qs at %L is an array and OPTIONAL; If it is not " + "present, then it cannot be the actual argument of " + "an ELEMENTAL procedure unless there is a non-optional" + " argument with the same rank " + "(Fortran 2018, 15.5.2.12)", + arg->expr->symtree->n.sym->name, &arg->expr->where); + } + } + + for (arg = arg0; arg; arg = arg->next) + { + if (arg->expr == NULL || arg->expr->rank == 0) + continue; + + /* Being elemental, the last upper bound of an assumed size array + argument must be present. */ + if (resolve_assumed_size_actual (arg->expr)) + return false; + + /* Elemental procedure's array actual arguments must conform. */ + if (e != NULL) + { + if (!gfc_check_conformance (arg->expr, e, _("elemental procedure"))) + return false; + } + else + e = arg->expr; + } + + /* INTENT(OUT) is only allowed for subroutines; if any actual argument + is an array, the intent inout/out variable needs to be also an array. */ + if (rank > 0 && esym && expr == NULL) + for (eformal = esym->formal, arg = arg0; arg && eformal; + arg = arg->next, eformal = eformal->next) + if ((eformal->sym->attr.intent == INTENT_OUT + || eformal->sym->attr.intent == INTENT_INOUT) + && arg->expr && arg->expr->rank == 0) + { + gfc_error ("Actual argument at %L for INTENT(%s) dummy %qs of " + "ELEMENTAL subroutine %qs is a scalar, but another " + "actual argument is an array", &arg->expr->where, + (eformal->sym->attr.intent == INTENT_OUT) ? "OUT" + : "INOUT", eformal->sym->name, esym->name); + return false; + } + return true; +} + + +/* This function does the checking of references to global procedures + as defined in sections 18.1 and 14.1, respectively, of the Fortran + 77 and 95 standards. It checks for a gsymbol for the name, making + one if it does not already exist. If it already exists, then the + reference being resolved must correspond to the type of gsymbol. + Otherwise, the new symbol is equipped with the attributes of the + reference. The corresponding code that is called in creating + global entities is parse.c. + + In addition, for all but -std=legacy, the gsymbols are used to + check the interfaces of external procedures from the same file. + The namespace of the gsymbol is resolved and then, once this is + done the interface is checked. */ + + +static bool +not_in_recursive (gfc_symbol *sym, gfc_namespace *gsym_ns) +{ + if (!gsym_ns->proc_name->attr.recursive) + return true; + + if (sym->ns == gsym_ns) + return false; + + if (sym->ns->parent && sym->ns->parent == gsym_ns) + return false; + + return true; +} + +static bool +not_entry_self_reference (gfc_symbol *sym, gfc_namespace *gsym_ns) +{ + if (gsym_ns->entries) + { + gfc_entry_list *entry = gsym_ns->entries; + + for (; entry; entry = entry->next) + { + if (strcmp (sym->name, entry->sym->name) == 0) + { + if (strcmp (gsym_ns->proc_name->name, + sym->ns->proc_name->name) == 0) + return false; + + if (sym->ns->parent + && strcmp (gsym_ns->proc_name->name, + sym->ns->parent->proc_name->name) == 0) + return false; + } + } + } + return true; +} + + +/* Check for the requirement of an explicit interface. F08:12.4.2.2. */ + +bool +gfc_explicit_interface_required (gfc_symbol *sym, char *errmsg, int err_len) +{ + gfc_formal_arglist *arg = gfc_sym_get_dummy_args (sym); + + for ( ; arg; arg = arg->next) + { + if (!arg->sym) + continue; + + if (arg->sym->attr.allocatable) /* (2a) */ + { + strncpy (errmsg, _("allocatable argument"), err_len); + return true; + } + else if (arg->sym->attr.asynchronous) + { + strncpy (errmsg, _("asynchronous argument"), err_len); + return true; + } + else if (arg->sym->attr.optional) + { + strncpy (errmsg, _("optional argument"), err_len); + return true; + } + else if (arg->sym->attr.pointer) + { + strncpy (errmsg, _("pointer argument"), err_len); + return true; + } + else if (arg->sym->attr.target) + { + strncpy (errmsg, _("target argument"), err_len); + return true; + } + else if (arg->sym->attr.value) + { + strncpy (errmsg, _("value argument"), err_len); + return true; + } + else if (arg->sym->attr.volatile_) + { + strncpy (errmsg, _("volatile argument"), err_len); + return true; + } + else if (arg->sym->as && arg->sym->as->type == AS_ASSUMED_SHAPE) /* (2b) */ + { + strncpy (errmsg, _("assumed-shape argument"), err_len); + return true; + } + else if (arg->sym->as && arg->sym->as->type == AS_ASSUMED_RANK) /* TS 29113, 6.2. */ + { + strncpy (errmsg, _("assumed-rank argument"), err_len); + return true; + } + else if (arg->sym->attr.codimension) /* (2c) */ + { + strncpy (errmsg, _("coarray argument"), err_len); + return true; + } + else if (false) /* (2d) TODO: parametrized derived type */ + { + strncpy (errmsg, _("parametrized derived type argument"), err_len); + return true; + } + else if (arg->sym->ts.type == BT_CLASS) /* (2e) */ + { + strncpy (errmsg, _("polymorphic argument"), err_len); + return true; + } + else if (arg->sym->attr.ext_attr & (1 << EXT_ATTR_NO_ARG_CHECK)) + { + strncpy (errmsg, _("NO_ARG_CHECK attribute"), err_len); + return true; + } + else if (arg->sym->ts.type == BT_ASSUMED) + { + /* As assumed-type is unlimited polymorphic (cf. above). + See also TS 29113, Note 6.1. */ + strncpy (errmsg, _("assumed-type argument"), err_len); + return true; + } + } + + if (sym->attr.function) + { + gfc_symbol *res = sym->result ? sym->result : sym; + + if (res->attr.dimension) /* (3a) */ + { + strncpy (errmsg, _("array result"), err_len); + return true; + } + else if (res->attr.pointer || res->attr.allocatable) /* (3b) */ + { + strncpy (errmsg, _("pointer or allocatable result"), err_len); + return true; + } + else if (res->ts.type == BT_CHARACTER && res->ts.u.cl + && res->ts.u.cl->length + && res->ts.u.cl->length->expr_type != EXPR_CONSTANT) /* (3c) */ + { + strncpy (errmsg, _("result with non-constant character length"), err_len); + return true; + } + } + + if (sym->attr.elemental && !sym->attr.intrinsic) /* (4) */ + { + strncpy (errmsg, _("elemental procedure"), err_len); + return true; + } + else if (sym->attr.is_bind_c) /* (5) */ + { + strncpy (errmsg, _("bind(c) procedure"), err_len); + return true; + } + + return false; +} + + +static void +resolve_global_procedure (gfc_symbol *sym, locus *where, int sub) +{ + gfc_gsymbol * gsym; + gfc_namespace *ns; + enum gfc_symbol_type type; + char reason[200]; + + type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION; + + gsym = gfc_get_gsymbol (sym->binding_label ? sym->binding_label : sym->name, + sym->binding_label != NULL); + + if ((gsym->type != GSYM_UNKNOWN && gsym->type != type)) + gfc_global_used (gsym, where); + + if ((sym->attr.if_source == IFSRC_UNKNOWN + || sym->attr.if_source == IFSRC_IFBODY) + && gsym->type != GSYM_UNKNOWN + && !gsym->binding_label + && gsym->ns + && gsym->ns->proc_name + && not_in_recursive (sym, gsym->ns) + && not_entry_self_reference (sym, gsym->ns)) + { + gfc_symbol *def_sym; + def_sym = gsym->ns->proc_name; + + if (gsym->ns->resolved != -1) + { + + /* Resolve the gsymbol namespace if needed. */ + if (!gsym->ns->resolved) + { + gfc_symbol *old_dt_list; + + /* Stash away derived types so that the backend_decls + do not get mixed up. */ + old_dt_list = gfc_derived_types; + gfc_derived_types = NULL; + + gfc_resolve (gsym->ns); + + /* Store the new derived types with the global namespace. */ + if (gfc_derived_types) + gsym->ns->derived_types = gfc_derived_types; + + /* Restore the derived types of this namespace. */ + gfc_derived_types = old_dt_list; + } + + /* Make sure that translation for the gsymbol occurs before + the procedure currently being resolved. */ + ns = gfc_global_ns_list; + for (; ns && ns != gsym->ns; ns = ns->sibling) + { + if (ns->sibling == gsym->ns) + { + ns->sibling = gsym->ns->sibling; + gsym->ns->sibling = gfc_global_ns_list; + gfc_global_ns_list = gsym->ns; + break; + } + } + + /* This can happen if a binding name has been specified. */ + if (gsym->binding_label && gsym->sym_name != def_sym->name) + gfc_find_symbol (gsym->sym_name, gsym->ns, 0, &def_sym); + + if (def_sym->attr.entry_master || def_sym->attr.entry) + { + gfc_entry_list *entry; + for (entry = gsym->ns->entries; entry; entry = entry->next) + if (strcmp (entry->sym->name, sym->name) == 0) + { + def_sym = entry->sym; + break; + } + } + } + + if (sym->attr.function && !gfc_compare_types (&sym->ts, &def_sym->ts)) + { + gfc_error ("Return type mismatch of function %qs at %L (%s/%s)", + sym->name, &sym->declared_at, gfc_typename (&sym->ts), + gfc_typename (&def_sym->ts)); + goto done; + } + + if (sym->attr.if_source == IFSRC_UNKNOWN + && gfc_explicit_interface_required (def_sym, reason, sizeof(reason))) + { + gfc_error ("Explicit interface required for %qs at %L: %s", + sym->name, &sym->declared_at, reason); + goto done; + } + + bool bad_result_characteristics; + if (!gfc_compare_interfaces (sym, def_sym, sym->name, 0, 1, + reason, sizeof(reason), NULL, NULL, + &bad_result_characteristics)) + { + /* Turn erros into warnings with -std=gnu and -std=legacy, + unless a function returns a wrong type, which can lead + to all kinds of ICEs and wrong code. */ + + if (!pedantic && (gfc_option.allow_std & GFC_STD_GNU) + && !bad_result_characteristics) + gfc_errors_to_warnings (true); + + gfc_error ("Interface mismatch in global procedure %qs at %L: %s", + sym->name, &sym->declared_at, reason); + sym->error = 1; + gfc_errors_to_warnings (false); + goto done; + } + } + +done: + + if (gsym->type == GSYM_UNKNOWN) + { + gsym->type = type; + gsym->where = *where; + } + + gsym->used = 1; +} + + +/************* 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; + + if (s->ts.type != BT_UNKNOWN) + expr->ts = s->ts; + else if (s->result != NULL && s->result->ts.type != BT_UNKNOWN) + expr->ts = s->result->ts; + + if (s->as != NULL) + expr->rank = s->as->rank; + else if (s->result != NULL && s->result->as != NULL) + expr->rank = s->result->as->rank; + + gfc_set_sym_referenced (expr->value.function.esym); + + 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 bool +resolve_generic_f (gfc_expr *expr) +{ + gfc_symbol *sym; + match m; + gfc_interface *intr = NULL; + + sym = expr->symtree->n.sym; + + for (;;) + { + m = resolve_generic_f0 (expr, sym); + if (m == MATCH_YES) + return true; + else if (m == MATCH_ERROR) + return false; + +generic: + if (!intr) + for (intr = sym->generic; intr; intr = intr->next) + if (gfc_fl_struct (intr->sym->attr.flavor)) + break; + + 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. See if the reference is to an intrinsic + that possesses a matching interface. 14.1.2.4 */ + if (sym && !intr && !gfc_is_intrinsic (sym, 0, expr->where)) + { + if (gfc_init_expr_flag) + gfc_error ("Function %qs in initialization expression at %L " + "must be an intrinsic function", + expr->symtree->n.sym->name, &expr->where); + else + gfc_error ("There is no specific function for the generic %qs " + "at %L", expr->symtree->n.sym->name, &expr->where); + return false; + } + + if (intr) + { + if (!gfc_convert_to_structure_constructor (expr, intr->sym, NULL, + NULL, false)) + return false; + if (!gfc_use_derived (expr->ts.u.derived)) + return false; + return resolve_structure_cons (expr, 0); + } + + m = gfc_intrinsic_func_interface (expr, 0); + if (m == MATCH_YES) + return true; + + if (m == MATCH_NO) + gfc_error ("Generic function %qs at %L is not consistent with a " + "specific intrinsic interface", expr->symtree->n.sym->name, + &expr->where); + + return false; +} + + +/* 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 %qs 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); + + if (sym->result) + expr->ts = sym->result->ts; + else + expr->ts = sym->ts; + expr->value.function.name = sym->name; + expr->value.function.esym = sym; + /* Prevent crash when sym->ts.u.derived->components is not set due to previous + error(s). */ + if (sym->ts.type == BT_CLASS && !CLASS_DATA (sym)) + return MATCH_ERROR; + if (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->as) + expr->rank = CLASS_DATA (sym)->as->rank; + else if (sym->as != NULL) + expr->rank = sym->as->rank; + + return MATCH_YES; +} + + +static bool +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 true; + if (m == MATCH_ERROR) + return false; + + 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 %qs at %L", + expr->symtree->n.sym->name, &expr->where); + + return true; +} + +/* Recursively append candidate SYM to CANDIDATES. Store the number of + candidates in CANDIDATES_LEN. */ + +static void +lookup_function_fuzzy_find_candidates (gfc_symtree *sym, + char **&candidates, + size_t &candidates_len) +{ + gfc_symtree *p; + + if (sym == NULL) + return; + if ((sym->n.sym->ts.type != BT_UNKNOWN || sym->n.sym->attr.external) + && sym->n.sym->attr.flavor == FL_PROCEDURE) + vec_push (candidates, candidates_len, sym->name); + + p = sym->left; + if (p) + lookup_function_fuzzy_find_candidates (p, candidates, candidates_len); + + p = sym->right; + if (p) + lookup_function_fuzzy_find_candidates (p, candidates, candidates_len); +} + + +/* Lookup function FN fuzzily, taking names in SYMROOT into account. */ + +const char* +gfc_lookup_function_fuzzy (const char *fn, gfc_symtree *symroot) +{ + char **candidates = NULL; + size_t candidates_len = 0; + lookup_function_fuzzy_find_candidates (symroot, candidates, candidates_len); + return gfc_closest_fuzzy_match (fn, candidates); +} + + +/* Resolve a procedure call not known to be generic nor specific. */ + +static bool +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_is_intrinsic (sym, 0, expr->where)) + { + if (gfc_intrinsic_func_interface (expr, 1) == MATCH_YES) + return true; + return false; + } + + /* IMPLICIT NONE (external) procedures require an explicit EXTERNAL attr. */ + /* Intrinsics were handled above, only non-intrinsics left here. */ + if (sym->attr.flavor == FL_PROCEDURE + && sym->attr.implicit_type + && sym->ns + && sym->ns->has_implicit_none_export) + { + gfc_error ("Missing explicit declaration with EXTERNAL attribute " + "for symbol %qs at %L", sym->name, &sym->declared_at); + sym->error = 1; + return false; + } + + /* 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->name, sym->ns); + + if (ts->type == BT_UNKNOWN) + { + const char *guessed + = gfc_lookup_function_fuzzy (sym->name, sym->ns->sym_root); + if (guessed) + gfc_error ("Function %qs at %L has no IMPLICIT type" + "; did you mean %qs?", + sym->name, &expr->where, guessed); + else + gfc_error ("Function %qs at %L has no IMPLICIT type", + sym->name, &expr->where); + return false; + } + else + expr->ts = *ts; + } + + return true; +} + + +/* Return true, if the symbol is an external procedure. */ +static bool +is_external_proc (gfc_symbol *sym) +{ + if (!sym->attr.dummy && !sym->attr.contained + && !gfc_is_intrinsic (sym, sym->attr.subroutine, sym->declared_at) + && sym->attr.proc != PROC_ST_FUNCTION + && !sym->attr.proc_pointer + && !sym->attr.use_assoc + && sym->name) + return true; + + return false; +} + + +/* Figure out if a function reference is pure or not. Also set the name + of the function for a potential error message. Return nonzero if the + function is PURE, zero if not. */ +static int +pure_stmt_function (gfc_expr *, gfc_symbol *); + +int +gfc_pure_function (gfc_expr *e, const char **name) +{ + int pure; + gfc_component *comp; + + *name = NULL; + + if (e->symtree != NULL + && e->symtree->n.sym != NULL + && e->symtree->n.sym->attr.proc == PROC_ST_FUNCTION) + return pure_stmt_function (e, e->symtree->n.sym); + + comp = gfc_get_proc_ptr_comp (e); + if (comp) + { + pure = gfc_pure (comp->ts.interface); + *name = comp->name; + } + else 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; +} + + +/* Check if the expression is a reference to an implicitly pure function. */ + +int +gfc_implicit_pure_function (gfc_expr *e) +{ + gfc_component *comp = gfc_get_proc_ptr_comp (e); + if (comp) + return gfc_implicit_pure (comp->ts.interface); + else if (e->value.function.esym) + return gfc_implicit_pure (e->value.function.esym); + else + return 0; +} + + +static bool +impure_stmt_fcn (gfc_expr *e, gfc_symbol *sym, + int *f ATTRIBUTE_UNUSED) +{ + const char *name; + + /* Don't bother recursing into other statement functions + since they will be checked individually for purity. */ + if (e->expr_type != EXPR_FUNCTION + || !e->symtree + || e->symtree->n.sym == sym + || e->symtree->n.sym->attr.proc == PROC_ST_FUNCTION) + return false; + + return gfc_pure_function (e, &name) ? false : true; +} + + +static int +pure_stmt_function (gfc_expr *e, gfc_symbol *sym) +{ + return gfc_traverse_expr (e, sym, impure_stmt_fcn, 0) ? 0 : 1; +} + + +/* Check if an impure function is allowed in the current context. */ + +static bool check_pure_function (gfc_expr *e) +{ + const char *name = NULL; + if (!gfc_pure_function (e, &name) && name) + { + if (forall_flag) + { + gfc_error ("Reference to impure function %qs at %L inside a " + "FORALL %s", name, &e->where, + forall_flag == 2 ? "mask" : "block"); + return false; + } + else if (gfc_do_concurrent_flag) + { + gfc_error ("Reference to impure function %qs at %L inside a " + "DO CONCURRENT %s", name, &e->where, + gfc_do_concurrent_flag == 2 ? "mask" : "block"); + return false; + } + else if (gfc_pure (NULL)) + { + gfc_error ("Reference to impure function %qs at %L " + "within a PURE procedure", name, &e->where); + return false; + } + if (!gfc_implicit_pure_function (e)) + gfc_unset_implicit_pure (NULL); + } + return true; +} + + +/* Update current procedure's array_outer_dependency flag, considering + a call to procedure SYM. */ + +static void +update_current_proc_array_outer_dependency (gfc_symbol *sym) +{ + /* Check to see if this is a sibling function that has not yet + been resolved. */ + gfc_namespace *sibling = gfc_current_ns->sibling; + for (; sibling; sibling = sibling->sibling) + { + if (sibling->proc_name == sym) + { + gfc_resolve (sibling); + break; + } + } + + /* If SYM has references to outer arrays, so has the procedure calling + SYM. If SYM is a procedure pointer, we can assume the worst. */ + if ((sym->attr.array_outer_dependency || sym->attr.proc_pointer) + && gfc_current_ns->proc_name) + gfc_current_ns->proc_name->attr.array_outer_dependency = 1; +} + + +/* Resolve a function call, which means resolving the arguments, then figuring + out which entity the name refers to. */ + +static bool +resolve_function (gfc_expr *expr) +{ + gfc_actual_arglist *arg; + gfc_symbol *sym; + bool t; + int temp; + procedure_type p = PROC_INTRINSIC; + bool no_formal_args; + + sym = NULL; + if (expr->symtree) + sym = expr->symtree->n.sym; + + /* If this is a procedure pointer component, it has already been resolved. */ + if (gfc_is_proc_ptr_comp (expr)) + return true; + + /* Avoid re-resolving the arguments of caf_get, which can lead to inserting + another caf_get. */ + if (sym && sym->attr.intrinsic + && (sym->intmod_sym_id == GFC_ISYM_CAF_GET + || sym->intmod_sym_id == GFC_ISYM_CAF_SEND)) + return true; + + if (expr->ref) + { + gfc_error ("Unexpected junk after %qs at %L", expr->symtree->n.sym->name, + &expr->where); + return false; + } + + if (sym && sym->attr.intrinsic + && !gfc_resolve_intrinsic (sym, &expr->where)) + return false; + + if (sym && (sym->attr.flavor == FL_VARIABLE || sym->attr.subroutine)) + { + gfc_error ("%qs at %L is not a function", sym->name, &expr->where); + return false; + } + + /* If this is a deferred TBP with an abstract interface (which may + of course be referenced), expr->value.function.esym will be set. */ + if (sym && sym->attr.abstract && !expr->value.function.esym) + { + gfc_error ("ABSTRACT INTERFACE %qs must not be referenced at %L", + sym->name, &expr->where); + return false; + } + + /* If this is a deferred TBP with an abstract interface, its result + cannot be an assumed length character (F2003: C418). */ + if (sym && sym->attr.abstract && sym->attr.function + && sym->result->ts.u.cl + && sym->result->ts.u.cl->length == NULL + && !sym->result->ts.deferred) + { + gfc_error ("ABSTRACT INTERFACE %qs at %L must not have an assumed " + "character length result (F2008: C418)", sym->name, + &sym->declared_at); + return false; + } + + /* Switch off assumed size checking and do this again for certain kinds + of procedure, once the procedure itself is resolved. */ + need_full_assumed_size++; + + if (expr->symtree && expr->symtree->n.sym) + p = expr->symtree->n.sym->attr.proc; + + if (expr->value.function.isym && expr->value.function.isym->inquiry) + inquiry_argument = true; + no_formal_args = sym && is_external_proc (sym) + && gfc_sym_get_dummy_args (sym) == NULL; + + if (!resolve_actual_arglist (expr->value.function.actual, + p, no_formal_args)) + { + inquiry_argument = false; + return false; + } + + inquiry_argument = false; + + /* Resume assumed_size checking. */ + need_full_assumed_size--; + + /* If the procedure is external, check for usage. */ + if (sym && is_external_proc (sym)) + resolve_global_procedure (sym, &expr->where, 0); + + if (sym && sym->ts.type == BT_CHARACTER + && sym->ts.u.cl + && sym->ts.u.cl->length == NULL + && !sym->attr.dummy + && !sym->ts.deferred + && expr->value.function.esym == NULL + && !sym->attr.contained) + { + /* Internal procedures are taken care of in resolve_contained_fntype. */ + gfc_error ("Function %qs is declared CHARACTER(*) and cannot " + "be used at %L since it is not a dummy argument", + sym->name, &expr->where); + return false; + } + + /* See if function is already resolved. */ + + if (expr->value.function.name != NULL + || expr->value.function.isym != NULL) + { + if (expr->ts.type == BT_UNKNOWN) + expr->ts = sym->ts; + t = true; + } + else + { + /* Apply the rules of section 14.1.2. */ + + switch (procedure_kind (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; + + /* Walk the argument list looking for invalid BOZ. */ + for (arg = expr->value.function.actual; arg; arg = arg->next) + if (arg->expr && arg->expr->ts.type == BT_BOZ) + { + gfc_error ("A BOZ literal constant at %L cannot appear as an " + "actual argument in a function reference", + &arg->expr->where); + return false; + } + + temp = need_full_assumed_size; + need_full_assumed_size = 0; + + if (!resolve_elemental_actual (expr, NULL)) + return false; + + if (omp_workshare_flag + && expr->value.function.esym + && ! gfc_elemental (expr->value.function.esym)) + { + gfc_error ("User defined non-ELEMENTAL function %qs at %L not allowed " + "in WORKSHARE construct", expr->value.function.esym->name, + &expr->where); + t = false; + } + +#define GENERIC_ID expr->value.function.isym->id + else if (expr->value.function.actual != NULL + && expr->value.function.isym != NULL + && GENERIC_ID != GFC_ISYM_LBOUND + && GENERIC_ID != GFC_ISYM_LCOBOUND + && GENERIC_ID != GFC_ISYM_UCOBOUND + && GENERIC_ID != GFC_ISYM_LEN + && GENERIC_ID != GFC_ISYM_LOC + && GENERIC_ID != GFC_ISYM_C_LOC + && GENERIC_ID != GFC_ISYM_PRESENT) + { + /* Array intrinsics must also have the last upper bound of an + assumed size array argument. UBOUND and SIZE have to be + excluded from the check if the second argument is anything + than a constant. */ + + for (arg = expr->value.function.actual; arg; arg = arg->next) + { + if ((GENERIC_ID == GFC_ISYM_UBOUND || GENERIC_ID == GFC_ISYM_SIZE) + && arg == expr->value.function.actual + && arg->next != NULL && arg->next->expr) + { + if (arg->next->expr->expr_type != EXPR_CONSTANT) + break; + + if (arg->next->name && strcmp (arg->next->name, "kind") == 0) + break; + + if ((int)mpz_get_si (arg->next->expr->value.integer) + < arg->expr->rank) + break; + } + + if (arg->expr != NULL + && arg->expr->rank > 0 + && resolve_assumed_size_actual (arg->expr)) + return false; + } + } +#undef GENERIC_ID + + need_full_assumed_size = temp; + + if (!check_pure_function(expr)) + t = false; + + /* Functions without the RECURSIVE attribution are not allowed to + * call themselves. */ + if (expr->value.function.esym && !expr->value.function.esym->attr.recursive) + { + gfc_symbol *esym; + esym = expr->value.function.esym; + + if (is_illegal_recursion (esym, gfc_current_ns)) + { + if (esym->attr.entry && esym->ns->entries) + gfc_error ("ENTRY %qs at %L cannot be called recursively, as" + " function %qs is not RECURSIVE", + esym->name, &expr->where, esym->ns->entries->sym->name); + else + gfc_error ("Function %qs at %L cannot be called recursively, as it" + " is not RECURSIVE", esym->name, &expr->where); + + t = false; + } + } + + /* Character lengths of use associated functions may contains references to + symbols not referenced from the current program unit otherwise. Make sure + those symbols are marked as referenced. */ + + if (expr->ts.type == BT_CHARACTER && expr->value.function.esym + && expr->value.function.esym->attr.use_assoc) + { + gfc_expr_set_symbols_referenced (expr->ts.u.cl->length); + } + + /* Make sure that the expression has a typespec that works. */ + if (expr->ts.type == BT_UNKNOWN) + { + if (expr->symtree->n.sym->result + && expr->symtree->n.sym->result->ts.type != BT_UNKNOWN + && !expr->symtree->n.sym->result->attr.proc_pointer) + expr->ts = expr->symtree->n.sym->result->ts; + } + + if (!expr->ref && !expr->value.function.isym) + { + if (expr->value.function.esym) + update_current_proc_array_outer_dependency (expr->value.function.esym); + else + update_current_proc_array_outer_dependency (sym); + } + else if (expr->ref) + /* typebound procedure: Assume the worst. */ + gfc_current_ns->proc_name->attr.array_outer_dependency = 1; + + if (expr->value.function.esym + && expr->value.function.esym->attr.ext_attr & (1 << EXT_ATTR_DEPRECATED)) + gfc_warning (OPT_Wdeprecated_declarations, + "Using function %qs at %L is deprecated", + sym->name, &expr->where); + return t; +} + + +/************* Subroutine resolution *************/ + +static bool +pure_subroutine (gfc_symbol *sym, const char *name, locus *loc) +{ + if (gfc_pure (sym)) + return true; + + if (forall_flag) + { + gfc_error ("Subroutine call to %qs in FORALL block at %L is not PURE", + name, loc); + return false; + } + else if (gfc_do_concurrent_flag) + { + gfc_error ("Subroutine call to %qs in DO CONCURRENT block at %L is not " + "PURE", name, loc); + return false; + } + else if (gfc_pure (NULL)) + { + gfc_error ("Subroutine call to %qs at %L is not PURE", name, loc); + return false; + } + + gfc_unset_implicit_pure (NULL); + return true; +} + + +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; + if (!pure_subroutine (s, s->name, &c->loc)) + return MATCH_ERROR; + 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 bool +resolve_generic_s (gfc_code *c) +{ + gfc_symbol *sym; + match m; + + sym = c->symtree->n.sym; + + for (;;) + { + m = resolve_generic_s0 (c, sym); + if (m == MATCH_YES) + return true; + else if (m == MATCH_ERROR) + return false; + +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. See if the reference is to an intrinsic + that possesses a matching interface. 14.1.2.4 */ + sym = c->symtree->n.sym; + + if (!gfc_is_intrinsic (sym, 1, c->loc)) + { + gfc_error ("There is no specific subroutine for the generic %qs at %L", + sym->name, &c->loc); + return false; + } + + m = gfc_intrinsic_sub_interface (c, 0); + if (m == MATCH_YES) + return true; + if (m == MATCH_NO) + gfc_error ("Generic subroutine %qs at %L is not consistent with an " + "intrinsic subroutine interface", sym->name, &c->loc); + + return false; +} + + +/* 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 %qs 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; + if (!pure_subroutine (sym, sym->name, &c->loc)) + return MATCH_ERROR; + + return MATCH_YES; +} + + +static bool +resolve_specific_s (gfc_code *c) +{ + gfc_symbol *sym; + match m; + + sym = c->symtree->n.sym; + + for (;;) + { + m = resolve_specific_s0 (c, sym); + if (m == MATCH_YES) + return true; + if (m == MATCH_ERROR) + return false; + + if (sym->ns->parent == NULL) + break; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym == NULL) + break; + } + + sym = c->symtree->n.sym; + gfc_error ("Unable to resolve the specific subroutine %qs at %L", + sym->name, &c->loc); + + return false; +} + + +/* Resolve a subroutine call not known to be generic nor specific. */ + +static bool +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_is_intrinsic (sym, 1, c->loc)) + { + if (gfc_intrinsic_sub_interface (c, 1) == MATCH_YES) + return true; + return false; + } + + /* The reference is to an external name. */ + +found: + gfc_procedure_use (sym, &c->ext.actual, &c->loc); + + c->resolved_sym = sym; + + return pure_subroutine (sym, sym->name, &c->loc); +} + + +/* 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 bool +resolve_call (gfc_code *c) +{ + bool t; + procedure_type ptype = PROC_INTRINSIC; + gfc_symbol *csym, *sym; + bool no_formal_args; + + csym = c->symtree ? c->symtree->n.sym : NULL; + + if (csym && csym->ts.type != BT_UNKNOWN) + { + gfc_error ("%qs at %L has a type, which is not consistent with " + "the CALL at %L", csym->name, &csym->declared_at, &c->loc); + return false; + } + + if (csym && gfc_current_ns->parent && csym->ns != gfc_current_ns) + { + gfc_symtree *st; + gfc_find_sym_tree (c->symtree->name, gfc_current_ns, 1, &st); + sym = st ? st->n.sym : NULL; + if (sym && csym != sym + && sym->ns == gfc_current_ns + && sym->attr.flavor == FL_PROCEDURE + && sym->attr.contained) + { + sym->refs++; + if (csym->attr.generic) + c->symtree->n.sym = sym; + else + c->symtree = st; + csym = c->symtree->n.sym; + } + } + + /* If this ia a deferred TBP, c->expr1 will be set. */ + if (!c->expr1 && csym) + { + if (csym->attr.abstract) + { + gfc_error ("ABSTRACT INTERFACE %qs must not be referenced at %L", + csym->name, &c->loc); + return false; + } + + /* Subroutines without the RECURSIVE attribution are not allowed to + call themselves. */ + if (is_illegal_recursion (csym, gfc_current_ns)) + { + if (csym->attr.entry && csym->ns->entries) + gfc_error ("ENTRY %qs at %L cannot be called recursively, " + "as subroutine %qs is not RECURSIVE", + csym->name, &c->loc, csym->ns->entries->sym->name); + else + gfc_error ("SUBROUTINE %qs at %L cannot be called recursively, " + "as it is not RECURSIVE", csym->name, &c->loc); + + t = false; + } + } + + /* Switch off assumed size checking and do this again for certain kinds + of procedure, once the procedure itself is resolved. */ + need_full_assumed_size++; + + if (csym) + ptype = csym->attr.proc; + + no_formal_args = csym && is_external_proc (csym) + && gfc_sym_get_dummy_args (csym) == NULL; + if (!resolve_actual_arglist (c->ext.actual, ptype, no_formal_args)) + return false; + + /* Resume assumed_size checking. */ + need_full_assumed_size--; + + /* If external, check for usage. */ + if (csym && is_external_proc (csym)) + resolve_global_procedure (csym, &c->loc, 1); + + t = true; + if (c->resolved_sym == NULL) + { + c->resolved_isym = NULL; + switch (procedure_kind (csym)) + { + 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"); + } + } + + /* Some checks of elemental subroutine actual arguments. */ + if (!resolve_elemental_actual (NULL, c)) + return false; + + if (!c->expr1) + update_current_proc_array_outer_dependency (csym); + else + /* Typebound procedure: Assume the worst. */ + gfc_current_ns->proc_name->attr.array_outer_dependency = 1; + + if (c->resolved_sym + && c->resolved_sym->attr.ext_attr & (1 << EXT_ATTR_DEPRECATED)) + gfc_warning (OPT_Wdeprecated_declarations, + "Using subroutine %qs at %L is deprecated", + c->resolved_sym->name, &c->loc); + + return t; +} + + +/* Compare the shapes of two arrays that have non-NULL shapes. If both + op1->shape and op2->shape are non-NULL return true if their shapes + match. If both op1->shape and op2->shape are non-NULL return false + if their shapes do not match. If either op1->shape or op2->shape is + NULL, return true. */ + +static bool +compare_shapes (gfc_expr *op1, gfc_expr *op2) +{ + bool t; + int i; + + t = true; + + if (op1->shape != NULL && op2->shape != NULL) + { + for (i = 0; i < op1->rank; i++) + { + if (mpz_cmp (op1->shape[i], op2->shape[i]) != 0) + { + gfc_error ("Shapes for operands at %L and %L are not conformable", + &op1->where, &op2->where); + t = false; + break; + } + } + } + + return t; +} + +/* Convert a logical operator to the corresponding bitwise intrinsic call. + For example A .AND. B becomes IAND(A, B). */ +static gfc_expr * +logical_to_bitwise (gfc_expr *e) +{ + gfc_expr *tmp, *op1, *op2; + gfc_isym_id isym; + gfc_actual_arglist *args = NULL; + + gcc_assert (e->expr_type == EXPR_OP); + + isym = GFC_ISYM_NONE; + op1 = e->value.op.op1; + op2 = e->value.op.op2; + + switch (e->value.op.op) + { + case INTRINSIC_NOT: + isym = GFC_ISYM_NOT; + break; + case INTRINSIC_AND: + isym = GFC_ISYM_IAND; + break; + case INTRINSIC_OR: + isym = GFC_ISYM_IOR; + break; + case INTRINSIC_NEQV: + isym = GFC_ISYM_IEOR; + break; + case INTRINSIC_EQV: + /* "Bitwise eqv" is just the complement of NEQV === IEOR. + Change the old expression to NEQV, which will get replaced by IEOR, + and wrap it in NOT. */ + tmp = gfc_copy_expr (e); + tmp->value.op.op = INTRINSIC_NEQV; + tmp = logical_to_bitwise (tmp); + isym = GFC_ISYM_NOT; + op1 = tmp; + op2 = NULL; + break; + default: + gfc_internal_error ("logical_to_bitwise(): Bad intrinsic"); + } + + /* Inherit the original operation's operands as arguments. */ + args = gfc_get_actual_arglist (); + args->expr = op1; + if (op2) + { + args->next = gfc_get_actual_arglist (); + args->next->expr = op2; + } + + /* Convert the expression to a function call. */ + e->expr_type = EXPR_FUNCTION; + e->value.function.actual = args; + e->value.function.isym = gfc_intrinsic_function_by_id (isym); + e->value.function.name = e->value.function.isym->name; + e->value.function.esym = NULL; + + /* Make up a pre-resolved function call symtree if we need to. */ + if (!e->symtree || !e->symtree->n.sym) + { + gfc_symbol *sym; + gfc_get_ha_sym_tree (e->value.function.isym->name, &e->symtree); + sym = e->symtree->n.sym; + sym->result = sym; + sym->attr.flavor = FL_PROCEDURE; + sym->attr.function = 1; + sym->attr.elemental = 1; + sym->attr.pure = 1; + sym->attr.referenced = 1; + gfc_intrinsic_symbol (sym); + gfc_commit_symbol (sym); + } + + args->name = e->value.function.isym->formal->name; + if (e->value.function.isym->formal->next) + args->next->name = e->value.function.isym->formal->next->name; + + return e; +} + +/* Recursively append candidate UOP to CANDIDATES. Store the number of + candidates in CANDIDATES_LEN. */ +static void +lookup_uop_fuzzy_find_candidates (gfc_symtree *uop, + char **&candidates, + size_t &candidates_len) +{ + gfc_symtree *p; + + if (uop == NULL) + return; + + /* Not sure how to properly filter here. Use all for a start. + n.uop.op is NULL for empty interface operators (is that legal?) disregard + these as i suppose they don't make terribly sense. */ + + if (uop->n.uop->op != NULL) + vec_push (candidates, candidates_len, uop->name); + + p = uop->left; + if (p) + lookup_uop_fuzzy_find_candidates (p, candidates, candidates_len); + + p = uop->right; + if (p) + lookup_uop_fuzzy_find_candidates (p, candidates, candidates_len); +} + +/* Lookup user-operator OP fuzzily, taking names in UOP into account. */ + +static const char* +lookup_uop_fuzzy (const char *op, gfc_symtree *uop) +{ + char **candidates = NULL; + size_t candidates_len = 0; + lookup_uop_fuzzy_find_candidates (uop, candidates, candidates_len); + return gfc_closest_fuzzy_match (op, candidates); +} + + +/* Callback finding an impure function as an operand to an .and. or + .or. expression. Remember the last function warned about to + avoid double warnings when recursing. */ + +static int +impure_function_callback (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + gfc_expr *f = *e; + const char *name; + static gfc_expr *last = NULL; + bool *found = (bool *) data; + + if (f->expr_type == EXPR_FUNCTION) + { + *found = 1; + if (f != last && !gfc_pure_function (f, &name) + && !gfc_implicit_pure_function (f)) + { + if (name) + gfc_warning (OPT_Wfunction_elimination, + "Impure function %qs at %L might not be evaluated", + name, &f->where); + else + gfc_warning (OPT_Wfunction_elimination, + "Impure function at %L might not be evaluated", + &f->where); + } + last = f; + } + + return 0; +} + +/* Return true if TYPE is character based, false otherwise. */ + +static int +is_character_based (bt type) +{ + return type == BT_CHARACTER || type == BT_HOLLERITH; +} + + +/* If expression is a hollerith, convert it to character and issue a warning + for the conversion. */ + +static void +convert_hollerith_to_character (gfc_expr *e) +{ + if (e->ts.type == BT_HOLLERITH) + { + gfc_typespec t; + gfc_clear_ts (&t); + t.type = BT_CHARACTER; + t.kind = e->ts.kind; + gfc_convert_type_warn (e, &t, 2, 1); + } +} + +/* Convert to numeric and issue a warning for the conversion. */ + +static void +convert_to_numeric (gfc_expr *a, gfc_expr *b) +{ + gfc_typespec t; + gfc_clear_ts (&t); + t.type = b->ts.type; + t.kind = b->ts.kind; + gfc_convert_type_warn (a, &t, 2, 1); +} + +/* Resolve an operator expression node. This can involve replacing the + operation with a user defined function call. */ + +static bool +resolve_operator (gfc_expr *e) +{ + gfc_expr *op1, *op2; + /* One error uses 3 names; additional space for wording (also via gettext). */ + char msg[3*GFC_MAX_SYMBOL_LEN + 1 + 50]; + bool dual_locus_error; + bool t = true; + + /* Resolve all subnodes-- give them types. */ + + switch (e->value.op.op) + { + default: + if (!gfc_resolve_expr (e->value.op.op2)) + t = false; + + /* Fall through. */ + + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + case INTRINSIC_PARENTHESES: + if (!gfc_resolve_expr (e->value.op.op1)) + return false; + if (e->value.op.op1 + && e->value.op.op1->ts.type == BT_BOZ && !e->value.op.op2) + { + gfc_error ("BOZ literal constant at %L cannot be an operand of " + "unary operator %qs", &e->value.op.op1->where, + gfc_op2string (e->value.op.op)); + return false; + } + break; + } + + /* Typecheck the new node. */ + + op1 = e->value.op.op1; + op2 = e->value.op.op2; + if (op1 == NULL && op2 == NULL) + return false; + /* Error out if op2 did not resolve. We already diagnosed op1. */ + if (t == false) + return false; + + dual_locus_error = false; + + /* op1 and op2 cannot both be BOZ. */ + if (op1 && op1->ts.type == BT_BOZ + && op2 && op2->ts.type == BT_BOZ) + { + gfc_error ("Operands at %L and %L cannot appear as operands of " + "binary operator %qs", &op1->where, &op2->where, + gfc_op2string (e->value.op.op)); + return false; + } + + if ((op1 && op1->expr_type == EXPR_NULL) + || (op2 && op2->expr_type == EXPR_NULL)) + { + snprintf (msg, sizeof (msg), + _("Invalid context for NULL() pointer at %%L")); + goto bad_op; + } + + switch (e->value.op.op) + { + 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; + } + + snprintf (msg, sizeof (msg), + _("Operand of unary numeric operator %%<%s%%> at %%L is %s"), + gfc_op2string (e->value.op.op), gfc_typename (e)); + 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, 1); + break; + } + + if (op1->ts.type == BT_DERIVED || op2->ts.type == BT_DERIVED) + snprintf (msg, sizeof (msg), + _("Unexpected derived-type entities in binary intrinsic " + "numeric operator %%<%s%%> at %%L"), + gfc_op2string (e->value.op.op)); + else + snprintf (msg, sizeof(msg), + _("Operands of binary numeric operator %%<%s%%> at %%L are %s/%s"), + gfc_op2string (e->value.op.op), gfc_typename (op1), + gfc_typename (op2)); + goto bad_op; + + case INTRINSIC_CONCAT: + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER + && op1->ts.kind == op2->ts.kind) + { + e->ts.type = BT_CHARACTER; + e->ts.kind = op1->ts.kind; + break; + } + + snprintf (msg, sizeof (msg), + _("Operands of string concatenation operator at %%L are %s/%s"), + gfc_typename (op1), gfc_typename (op2)); + 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); + + if (flag_frontend_optimize && + (e->value.op.op == INTRINSIC_AND || e->value.op.op == INTRINSIC_OR)) + { + /* Warn about short-circuiting + with impure function as second operand. */ + bool op2_f = false; + gfc_expr_walker (&op2, impure_function_callback, &op2_f); + } + break; + } + + /* Logical ops on integers become bitwise ops with -fdec. */ + else if (flag_dec + && (op1->ts.type == BT_INTEGER || op2->ts.type == BT_INTEGER)) + { + e->ts.type = BT_INTEGER; + e->ts.kind = gfc_kind_max (op1, op2); + if (op1->ts.type != e->ts.type || op1->ts.kind != e->ts.kind) + gfc_convert_type (op1, &e->ts, 1); + if (op2->ts.type != e->ts.type || op2->ts.kind != e->ts.kind) + gfc_convert_type (op2, &e->ts, 1); + e = logical_to_bitwise (e); + goto simplify_op; + } + + snprintf (msg, sizeof (msg), + _("Operands of logical operator %%<%s%%> at %%L are %s/%s"), + gfc_op2string (e->value.op.op), gfc_typename (op1), + gfc_typename (op2)); + + goto bad_op; + + case INTRINSIC_NOT: + /* Logical ops on integers become bitwise ops with -fdec. */ + if (flag_dec && op1->ts.type == BT_INTEGER) + { + e->ts.type = BT_INTEGER; + e->ts.kind = op1->ts.kind; + e = logical_to_bitwise (e); + goto simplify_op; + } + + if (op1->ts.type == BT_LOGICAL) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = op1->ts.kind; + break; + } + + snprintf (msg, sizeof (msg), _("Operand of .not. operator at %%L is %s"), + gfc_typename (op1)); + goto bad_op; + + case INTRINSIC_GT: + case INTRINSIC_GT_OS: + case INTRINSIC_GE: + case INTRINSIC_GE_OS: + case INTRINSIC_LT: + case INTRINSIC_LT_OS: + case INTRINSIC_LE: + case INTRINSIC_LE_OS: + 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_EQ_OS: + case INTRINSIC_NE: + case INTRINSIC_NE_OS: + + if (flag_dec + && is_character_based (op1->ts.type) + && is_character_based (op2->ts.type)) + { + convert_hollerith_to_character (op1); + convert_hollerith_to_character (op2); + } + + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER + && op1->ts.kind == op2->ts.kind) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_default_logical_kind; + break; + } + + /* If op1 is BOZ, then op2 is not!. Try to convert to type of op2. */ + if (op1->ts.type == BT_BOZ) + { + if (gfc_invalid_boz (G_("BOZ literal constant near %L cannot appear " + "as an operand of a relational operator"), + &op1->where)) + return false; + + if (op2->ts.type == BT_INTEGER && !gfc_boz2int (op1, op2->ts.kind)) + return false; + + if (op2->ts.type == BT_REAL && !gfc_boz2real (op1, op2->ts.kind)) + return false; + } + + /* If op2 is BOZ, then op1 is not!. Try to convert to type of op2. */ + if (op2->ts.type == BT_BOZ) + { + if (gfc_invalid_boz (G_("BOZ literal constant near %L cannot appear" + " as an operand of a relational operator"), + &op2->where)) + return false; + + if (op1->ts.type == BT_INTEGER && !gfc_boz2int (op2, op1->ts.kind)) + return false; + + if (op1->ts.type == BT_REAL && !gfc_boz2real (op2, op1->ts.kind)) + return false; + } + if (flag_dec + && op1->ts.type == BT_HOLLERITH && gfc_numeric_ts (&op2->ts)) + convert_to_numeric (op1, op2); + + if (flag_dec + && gfc_numeric_ts (&op1->ts) && op2->ts.type == BT_HOLLERITH) + convert_to_numeric (op2, op1); + + if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts)) + { + gfc_type_convert_binary (e, 1); + + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_default_logical_kind; + + if (warn_compare_reals) + { + gfc_intrinsic_op op = e->value.op.op; + + /* Type conversion has made sure that the types of op1 and op2 + agree, so it is only necessary to check the first one. */ + if ((op1->ts.type == BT_REAL || op1->ts.type == BT_COMPLEX) + && (op == INTRINSIC_EQ || op == INTRINSIC_EQ_OS + || op == INTRINSIC_NE || op == INTRINSIC_NE_OS)) + { + const char *msg; + + if (op == INTRINSIC_EQ || op == INTRINSIC_EQ_OS) + msg = G_("Equality comparison for %s at %L"); + else + msg = G_("Inequality comparison for %s at %L"); + + gfc_warning (OPT_Wcompare_reals, msg, + gfc_typename (op1), &op1->where); + } + } + + break; + } + + if (op1->ts.type == BT_LOGICAL && op2->ts.type == BT_LOGICAL) + snprintf (msg, sizeof (msg), + _("Logicals at %%L must be compared with %s instead of %s"), + (e->value.op.op == INTRINSIC_EQ + || e->value.op.op == INTRINSIC_EQ_OS) + ? ".eqv." : ".neqv.", gfc_op2string (e->value.op.op)); + else + snprintf (msg, sizeof (msg), + _("Operands of comparison operator %%<%s%%> at %%L are %s/%s"), + gfc_op2string (e->value.op.op), gfc_typename (op1), + gfc_typename (op2)); + + goto bad_op; + + case INTRINSIC_USER: + if (e->value.op.uop->op == NULL) + { + const char *name = e->value.op.uop->name; + const char *guessed; + guessed = lookup_uop_fuzzy (name, e->value.op.uop->ns->uop_root); + if (guessed) + snprintf (msg, sizeof (msg), + _("Unknown operator %%<%s%%> at %%L; did you mean '%s'?"), + name, guessed); + else + snprintf (msg, sizeof (msg), _("Unknown operator %%<%s%%> at %%L"), + name); + } + else if (op2 == NULL) + snprintf (msg, sizeof (msg), + _("Operand of user operator %%<%s%%> at %%L is %s"), + e->value.op.uop->name, gfc_typename (op1)); + else + { + snprintf (msg, sizeof (msg), + _("Operands of user operator %%<%s%%> at %%L are %s/%s"), + e->value.op.uop->name, gfc_typename (op1), + gfc_typename (op2)); + e->value.op.uop->op->sym->attr.referenced = 1; + } + + goto bad_op; + + case INTRINSIC_PARENTHESES: + e->ts = op1->ts; + if (e->ts.type == BT_CHARACTER) + e->ts.u.cl = op1->ts.u.cl; + break; + + default: + gfc_internal_error ("resolve_operator(): Bad intrinsic"); + } + + /* Deal with arrayness of an operand through an operator. */ + + switch (e->value.op.op) + { + 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_EQ_OS: + case INTRINSIC_NE: + case INTRINSIC_NE_OS: + case INTRINSIC_GT: + case INTRINSIC_GT_OS: + case INTRINSIC_GE: + case INTRINSIC_GE_OS: + case INTRINSIC_LT: + case INTRINSIC_LT_OS: + case INTRINSIC_LE: + case INTRINSIC_LE_OS: + + 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) + { + t = compare_shapes (op1, op2); + if (!t) + e->shape = NULL; + else + e->shape = gfc_copy_shape (op1->shape, op1->rank); + } + } + else + { + /* Allow higher level expressions to work. */ + e->rank = 0; + + /* Try user-defined operators, and otherwise throw an error. */ + dual_locus_error = true; + snprintf (msg, sizeof (msg), + _("Inconsistent ranks for operator at %%L and %%L")); + goto bad_op; + } + } + + break; + + case INTRINSIC_PARENTHESES: + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + /* Simply copy arrayness attribute */ + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + + break; + + default: + break; + } + +simplify_op: + + /* Attempt to simplify the expression. */ + if (t) + { + t = gfc_simplify_expr (e, 0); + /* Some calls do not succeed in simplification and return false + even though there is no error; e.g. variable references to + PARAMETER arrays. */ + if (!gfc_is_constant_expr (e)) + t = true; + } + return t; + +bad_op: + + { + match m = gfc_extend_expr (e); + if (m == MATCH_YES) + return true; + if (m == MATCH_ERROR) + return false; + } + + if (dual_locus_error) + gfc_error (msg, &op1->where, &op2->where); + else + gfc_error (msg, &e->where); + + return false; +} + + +/************** Array resolution subroutines **************/ + +enum compare_result +{ CMP_LT, CMP_EQ, CMP_GT, CMP_UNKNOWN }; + +/* Compare two integer expressions. */ + +static compare_result +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 either of the types isn't INTEGER, we must have + raised an error earlier. */ + + if (a->ts.type != BT_INTEGER || b->ts.type != BT_INTEGER) + return CMP_UNKNOWN; + + 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 compare_result +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 an integer expression with a mpz_t. */ + +static compare_result +compare_bound_mpz_t (gfc_expr *a, mpz_t 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 (a->value.integer, b); + + if (i < 0) + return CMP_LT; + if (i > 0) + return CMP_GT; + return CMP_EQ; +} + + +/* Compute the last value of a sequence given by a triplet. + Return 0 if it wasn't able to compute the last value, or if the + sequence if empty, and 1 otherwise. */ + +static int +compute_last_value_for_triplet (gfc_expr *start, gfc_expr *end, + gfc_expr *stride, mpz_t last) +{ + mpz_t rem; + + if (start == NULL || start->expr_type != EXPR_CONSTANT + || end == NULL || end->expr_type != EXPR_CONSTANT + || (stride != NULL && stride->expr_type != EXPR_CONSTANT)) + return 0; + + if (start->ts.type != BT_INTEGER || end->ts.type != BT_INTEGER + || (stride != NULL && stride->ts.type != BT_INTEGER)) + return 0; + + if (stride == NULL || compare_bound_int (stride, 1) == CMP_EQ) + { + if (compare_bound (start, end) == CMP_GT) + return 0; + mpz_set (last, end->value.integer); + return 1; + } + + if (compare_bound_int (stride, 0) == CMP_GT) + { + /* Stride is positive */ + if (mpz_cmp (start->value.integer, end->value.integer) > 0) + return 0; + } + else + { + /* Stride is negative */ + if (mpz_cmp (start->value.integer, end->value.integer) < 0) + return 0; + } + + mpz_init (rem); + mpz_sub (rem, end->value.integer, start->value.integer); + mpz_tdiv_r (rem, rem, stride->value.integer); + mpz_sub (last, end->value.integer, rem); + mpz_clear (rem); + + return 1; +} + + +/* Compare a single dimension of an array reference to the array + specification. */ + +static bool +check_dimension (int i, gfc_array_ref *ar, gfc_array_spec *as) +{ + mpz_t last_value; + + if (ar->dimen_type[i] == DIMEN_STAR) + { + gcc_assert (ar->stride[i] == NULL); + /* This implies [*] as [*:] and [*:3] are not possible. */ + if (ar->start[i] == NULL) + { + gcc_assert (ar->end[i] == NULL); + return true; + } + } + +/* Given start, end and stride values, calculate the minimum and + maximum referenced indexes. */ + + switch (ar->dimen_type[i]) + { + case DIMEN_VECTOR: + case DIMEN_THIS_IMAGE: + break; + + case DIMEN_STAR: + case DIMEN_ELEMENT: + if (compare_bound (ar->start[i], as->lower[i]) == CMP_LT) + { + if (i < as->rank) + gfc_warning (0, "Array reference at %L is out of bounds " + "(%ld < %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (ar->start[i]->value.integer), + mpz_get_si (as->lower[i]->value.integer), i+1); + else + gfc_warning (0, "Array reference at %L is out of bounds " + "(%ld < %ld) in codimension %d", &ar->c_where[i], + mpz_get_si (ar->start[i]->value.integer), + mpz_get_si (as->lower[i]->value.integer), + i + 1 - as->rank); + return true; + } + if (compare_bound (ar->start[i], as->upper[i]) == CMP_GT) + { + if (i < as->rank) + gfc_warning (0, "Array reference at %L is out of bounds " + "(%ld > %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (ar->start[i]->value.integer), + mpz_get_si (as->upper[i]->value.integer), i+1); + else + gfc_warning (0, "Array reference at %L is out of bounds " + "(%ld > %ld) in codimension %d", &ar->c_where[i], + mpz_get_si (ar->start[i]->value.integer), + mpz_get_si (as->upper[i]->value.integer), + i + 1 - as->rank); + return true; + } + + break; + + case DIMEN_RANGE: + { +#define AR_START (ar->start[i] ? ar->start[i] : as->lower[i]) +#define AR_END (ar->end[i] ? ar->end[i] : as->upper[i]) + + compare_result comp_start_end = compare_bound (AR_START, AR_END); + + /* Check for zero stride, which is not allowed. */ + if (compare_bound_int (ar->stride[i], 0) == CMP_EQ) + { + gfc_error ("Illegal stride of zero at %L", &ar->c_where[i]); + return false; + } + + /* if start == len || (stride > 0 && start < len) + || (stride < 0 && start > len), + then the array section contains at least one element. In this + case, there is an out-of-bounds access if + (start < lower || start > upper). */ + if (compare_bound (AR_START, AR_END) == CMP_EQ + || ((compare_bound_int (ar->stride[i], 0) == CMP_GT + || ar->stride[i] == NULL) && comp_start_end == CMP_LT) + || (compare_bound_int (ar->stride[i], 0) == CMP_LT + && comp_start_end == CMP_GT)) + { + if (compare_bound (AR_START, as->lower[i]) == CMP_LT) + { + gfc_warning (0, "Lower array reference at %L is out of bounds " + "(%ld < %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (AR_START->value.integer), + mpz_get_si (as->lower[i]->value.integer), i+1); + return true; + } + if (compare_bound (AR_START, as->upper[i]) == CMP_GT) + { + gfc_warning (0, "Lower array reference at %L is out of bounds " + "(%ld > %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (AR_START->value.integer), + mpz_get_si (as->upper[i]->value.integer), i+1); + return true; + } + } + + /* If we can compute the highest index of the array section, + then it also has to be between lower and upper. */ + mpz_init (last_value); + if (compute_last_value_for_triplet (AR_START, AR_END, ar->stride[i], + last_value)) + { + if (compare_bound_mpz_t (as->lower[i], last_value) == CMP_GT) + { + gfc_warning (0, "Upper array reference at %L is out of bounds " + "(%ld < %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (last_value), + mpz_get_si (as->lower[i]->value.integer), i+1); + mpz_clear (last_value); + return true; + } + if (compare_bound_mpz_t (as->upper[i], last_value) == CMP_LT) + { + gfc_warning (0, "Upper array reference at %L is out of bounds " + "(%ld > %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (last_value), + mpz_get_si (as->upper[i]->value.integer), i+1); + mpz_clear (last_value); + return true; + } + } + mpz_clear (last_value); + +#undef AR_START +#undef AR_END + } + break; + + default: + gfc_internal_error ("check_dimension(): Bad array reference"); + } + + return true; +} + + +/* Compare an array reference with an array specification. */ + +static bool +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 false; + } + + if (ar->type == AR_FULL) + return true; + + if (as->rank != ar->dimen) + { + gfc_error ("Rank mismatch in array reference at %L (%d/%d)", + &ar->where, ar->dimen, as->rank); + return false; + } + + /* ar->codimen == 0 is a local array. */ + if (as->corank != ar->codimen && ar->codimen != 0) + { + gfc_error ("Coindex rank mismatch in array reference at %L (%d/%d)", + &ar->where, ar->codimen, as->corank); + return false; + } + + for (i = 0; i < as->rank; i++) + if (!check_dimension (i, ar, as)) + return false; + + /* Local access has no coarray spec. */ + if (ar->codimen != 0) + for (i = as->rank; i < as->rank + as->corank; i++) + { + if (ar->dimen_type[i] != DIMEN_ELEMENT && !ar->in_allocate + && ar->dimen_type[i] != DIMEN_THIS_IMAGE) + { + gfc_error ("Coindex of codimension %d must be a scalar at %L", + i + 1 - as->rank, &ar->where); + return false; + } + if (!check_dimension (i, ar, as)) + return false; + } + + return true; +} + + +/* Resolve one part of an array index. */ + +static bool +gfc_resolve_index_1 (gfc_expr *index, int check_scalar, + int force_index_integer_kind) +{ + gfc_typespec ts; + + if (index == NULL) + return true; + + if (!gfc_resolve_expr (index)) + return false; + + if (check_scalar && index->rank != 0) + { + gfc_error ("Array index at %L must be scalar", &index->where); + return false; + } + + if (index->ts.type != BT_INTEGER && index->ts.type != BT_REAL) + { + gfc_error ("Array index at %L must be of INTEGER type, found %s", + &index->where, gfc_basic_typename (index->ts.type)); + return false; + } + + if (index->ts.type == BT_REAL) + if (!gfc_notify_std (GFC_STD_LEGACY, "REAL array index at %L", + &index->where)) + return false; + + if ((index->ts.kind != gfc_index_integer_kind + && force_index_integer_kind) + || index->ts.type != BT_INTEGER) + { + gfc_clear_ts (&ts); + ts.type = BT_INTEGER; + ts.kind = gfc_index_integer_kind; + + gfc_convert_type_warn (index, &ts, 2, 0); + } + + return true; +} + +/* Resolve one part of an array index. */ + +bool +gfc_resolve_index (gfc_expr *index, int check_scalar) +{ + return gfc_resolve_index_1 (index, check_scalar, 1); +} + +/* Resolve a dim argument to an intrinsic function. */ + +bool +gfc_resolve_dim_arg (gfc_expr *dim) +{ + if (dim == NULL) + return true; + + if (!gfc_resolve_expr (dim)) + return false; + + if (dim->rank != 0) + { + gfc_error ("Argument dim at %L must be scalar", &dim->where); + return false; + + } + + if (dim->ts.type != BT_INTEGER) + { + gfc_error ("Argument dim at %L must be of INTEGER type", &dim->where); + return false; + } + + if (dim->ts.kind != gfc_index_integer_kind) + { + gfc_typespec ts; + + gfc_clear_ts (&ts); + ts.type = BT_INTEGER; + ts.kind = gfc_index_integer_kind; + + gfc_convert_type_warn (dim, &ts, 2, 0); + } + + return true; +} + +/* 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 +resolve_assoc_var (gfc_symbol* sym, bool resolve_target); + +static void +find_array_spec (gfc_expr *e) +{ + gfc_array_spec *as; + gfc_component *c; + gfc_ref *ref; + bool class_as = false; + + if (e->symtree->n.sym->assoc) + { + if (e->symtree->n.sym->assoc->target) + gfc_resolve_expr (e->symtree->n.sym->assoc->target); + resolve_assoc_var (e->symtree->n.sym, false); + } + + if (e->symtree->n.sym->ts.type == BT_CLASS) + { + as = CLASS_DATA (e->symtree->n.sym)->as; + class_as = true; + } + else + as = e->symtree->n.sym->as; + + 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: + c = ref->u.c.component; + if (c->attr.dimension) + { + if (as != NULL && !(class_as && as == c->as)) + gfc_internal_error ("find_array_spec(): unused as(1)"); + as = c->as; + } + + break; + + case REF_SUBSTRING: + case REF_INQUIRY: + break; + } + + if (as != NULL) + gfc_internal_error ("find_array_spec(): unused as(2)"); +} + + +/* Resolve an array reference. */ + +static bool +resolve_array_ref (gfc_array_ref *ar) +{ + int i, check_scalar; + gfc_expr *e; + + for (i = 0; i < ar->dimen + ar->codimen; i++) + { + check_scalar = ar->dimen_type[i] == DIMEN_RANGE; + + /* Do not force gfc_index_integer_kind for the start. We can + do fine with any integer kind. This avoids temporary arrays + created for indexing with a vector. */ + if (!gfc_resolve_index_1 (ar->start[i], check_scalar, 0)) + return false; + if (!gfc_resolve_index (ar->end[i], check_scalar)) + return false; + if (!gfc_resolve_index (ar->stride[i], check_scalar)) + return false; + + e = ar->start[i]; + + if (ar->dimen_type[i] == DIMEN_UNKNOWN) + switch (e->rank) + { + case 0: + ar->dimen_type[i] = DIMEN_ELEMENT; + break; + + case 1: + ar->dimen_type[i] = DIMEN_VECTOR; + if (e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->ts.type == BT_DERIVED) + ar->start[i] = gfc_get_parentheses (e); + break; + + default: + gfc_error ("Array index at %L is an array of rank %d", + &ar->c_where[i], e->rank); + return false; + } + + /* Fill in the upper bound, which may be lower than the + specified one for something like a(2:10:5), which is + identical to a(2:7:5). Only relevant for strides not equal + to one. Don't try a division by zero. */ + if (ar->dimen_type[i] == DIMEN_RANGE + && ar->stride[i] != NULL && ar->stride[i]->expr_type == EXPR_CONSTANT + && mpz_cmp_si (ar->stride[i]->value.integer, 1L) != 0 + && mpz_cmp_si (ar->stride[i]->value.integer, 0L) != 0) + { + mpz_t size, end; + + if (gfc_ref_dimen_size (ar, i, &size, &end)) + { + if (ar->end[i] == NULL) + { + ar->end[i] = + gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind, + &ar->where); + mpz_set (ar->end[i]->value.integer, end); + } + else if (ar->end[i]->ts.type == BT_INTEGER + && ar->end[i]->expr_type == EXPR_CONSTANT) + { + mpz_set (ar->end[i]->value.integer, end); + } + else + gcc_unreachable (); + + mpz_clear (size); + mpz_clear (end); + } + } + } + + if (ar->type == AR_FULL) + { + if (ar->as->rank == 0) + ar->type = AR_ELEMENT; + + /* Make sure array is the same as array(:,:), this way + we don't need to special case all the time. */ + ar->dimen = ar->as->rank; + for (i = 0; i < ar->dimen; i++) + { + ar->dimen_type[i] = DIMEN_RANGE; + + gcc_assert (ar->start[i] == NULL); + gcc_assert (ar->end[i] == NULL); + gcc_assert (ar->stride[i] == NULL); + } + } + + /* 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 (!ar->as->cray_pointee && !compare_spec_to_ref (ar)) + return false; + + if (ar->as->corank && ar->codimen == 0) + { + int n; + ar->codimen = ar->as->corank; + for (n = ar->dimen; n < ar->dimen + ar->codimen; n++) + ar->dimen_type[n] = DIMEN_THIS_IMAGE; + } + + return true; +} + + +bool +gfc_resolve_substring (gfc_ref *ref, bool *equal_length) +{ + int k = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind, false); + + if (ref->u.ss.start != NULL) + { + if (!gfc_resolve_expr (ref->u.ss.start)) + return false; + + 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 false; + } + + if (ref->u.ss.start->rank != 0) + { + gfc_error ("Substring start index at %L must be scalar", + &ref->u.ss.start->where); + return false; + } + + if (compare_bound_int (ref->u.ss.start, 1) == CMP_LT + && (compare_bound (ref->u.ss.end, ref->u.ss.start) == CMP_EQ + || compare_bound (ref->u.ss.end, ref->u.ss.start) == CMP_GT)) + { + gfc_error ("Substring start index at %L is less than one", + &ref->u.ss.start->where); + return false; + } + } + + if (ref->u.ss.end != NULL) + { + if (!gfc_resolve_expr (ref->u.ss.end)) + return false; + + 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 false; + } + + if (ref->u.ss.end->rank != 0) + { + gfc_error ("Substring end index at %L must be scalar", + &ref->u.ss.end->where); + return false; + } + + if (ref->u.ss.length != NULL + && compare_bound (ref->u.ss.end, ref->u.ss.length->length) == CMP_GT + && (compare_bound (ref->u.ss.end, ref->u.ss.start) == CMP_EQ + || compare_bound (ref->u.ss.end, ref->u.ss.start) == CMP_GT)) + { + gfc_error ("Substring end index at %L exceeds the string length", + &ref->u.ss.start->where); + return false; + } + + if (compare_bound_mpz_t (ref->u.ss.end, + gfc_integer_kinds[k].huge) == CMP_GT + && (compare_bound (ref->u.ss.end, ref->u.ss.start) == CMP_EQ + || compare_bound (ref->u.ss.end, ref->u.ss.start) == CMP_GT)) + { + gfc_error ("Substring end index at %L is too large", + &ref->u.ss.end->where); + return false; + } + /* If the substring has the same length as the original + variable, the reference itself can be deleted. */ + + if (ref->u.ss.length != NULL + && compare_bound (ref->u.ss.end, ref->u.ss.length->length) == CMP_EQ + && compare_bound_int (ref->u.ss.start, 1) == CMP_EQ) + *equal_length = true; + } + + return true; +} + + +/* This function supplies missing substring charlens. */ + +void +gfc_resolve_substring_charlen (gfc_expr *e) +{ + gfc_ref *char_ref; + gfc_expr *start, *end; + gfc_typespec *ts = NULL; + mpz_t diff; + + for (char_ref = e->ref; char_ref; char_ref = char_ref->next) + { + if (char_ref->type == REF_SUBSTRING || char_ref->type == REF_INQUIRY) + break; + if (char_ref->type == REF_COMPONENT) + ts = &char_ref->u.c.component->ts; + } + + if (!char_ref || char_ref->type == REF_INQUIRY) + return; + + gcc_assert (char_ref->next == NULL); + + if (e->ts.u.cl) + { + if (e->ts.u.cl->length) + gfc_free_expr (e->ts.u.cl->length); + else if (e->expr_type == EXPR_VARIABLE && e->symtree->n.sym->attr.dummy) + return; + } + + if (!e->ts.u.cl) + e->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL); + + if (char_ref->u.ss.start) + start = gfc_copy_expr (char_ref->u.ss.start); + else + start = gfc_get_int_expr (gfc_charlen_int_kind, NULL, 1); + + if (char_ref->u.ss.end) + end = gfc_copy_expr (char_ref->u.ss.end); + else if (e->expr_type == EXPR_VARIABLE) + { + if (!ts) + ts = &e->symtree->n.sym->ts; + end = gfc_copy_expr (ts->u.cl->length); + } + else + end = NULL; + + if (!start || !end) + { + gfc_free_expr (start); + gfc_free_expr (end); + return; + } + + /* Length = (end - start + 1). + Check first whether it has a constant length. */ + if (gfc_dep_difference (end, start, &diff)) + { + gfc_expr *len = gfc_get_constant_expr (BT_INTEGER, gfc_charlen_int_kind, + &e->where); + + mpz_add_ui (len->value.integer, diff, 1); + mpz_clear (diff); + e->ts.u.cl->length = len; + /* The check for length < 0 is handled below */ + } + else + { + e->ts.u.cl->length = gfc_subtract (end, start); + e->ts.u.cl->length = gfc_add (e->ts.u.cl->length, + gfc_get_int_expr (gfc_charlen_int_kind, + NULL, 1)); + } + + /* F2008, 6.4.1: Both the starting point and the ending point shall + be within the range 1, 2, ..., n unless the starting point exceeds + the ending point, in which case the substring has length zero. */ + + if (mpz_cmp_si (e->ts.u.cl->length->value.integer, 0) < 0) + mpz_set_si (e->ts.u.cl->length->value.integer, 0); + + e->ts.u.cl->length->ts.type = BT_INTEGER; + e->ts.u.cl->length->ts.kind = gfc_charlen_int_kind; + + /* Make sure that the length is simplified. */ + gfc_simplify_expr (e->ts.u.cl->length, 1); + gfc_resolve_expr (e->ts.u.cl->length); +} + + +/* Resolve subtype references. */ + +bool +gfc_resolve_ref (gfc_expr *expr) +{ + int current_part_dimension, n_components, seen_part_dimension, dim; + gfc_ref *ref, **prev, *array_ref; + bool equal_length; + + for (ref = expr->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->u.ar.as == NULL) + { + find_array_spec (expr); + break; + } + + for (prev = &expr->ref; *prev != NULL; + prev = *prev == NULL ? prev : &(*prev)->next) + switch ((*prev)->type) + { + case REF_ARRAY: + if (!resolve_array_ref (&(*prev)->u.ar)) + return false; + break; + + case REF_COMPONENT: + case REF_INQUIRY: + break; + + case REF_SUBSTRING: + equal_length = false; + if (!gfc_resolve_substring (*prev, &equal_length)) + return false; + + if (expr->expr_type != EXPR_SUBSTRING && equal_length) + { + /* Remove the reference and move the charlen, if any. */ + ref = *prev; + *prev = ref->next; + ref->next = NULL; + expr->ts.u.cl = ref->u.ss.length; + ref->u.ss.length = NULL; + gfc_free_ref_list (ref); + } + break; + } + + /* Check constraints on part references. */ + + current_part_dimension = 0; + seen_part_dimension = 0; + n_components = 0; + array_ref = NULL; + + for (ref = expr->ref; ref; ref = ref->next) + { + switch (ref->type) + { + case REF_ARRAY: + array_ref = ref; + switch (ref->u.ar.type) + { + case AR_FULL: + /* Coarray scalar. */ + if (ref->u.ar.as->rank == 0) + { + current_part_dimension = 0; + break; + } + /* Fall through. */ + case AR_SECTION: + current_part_dimension = 1; + break; + + case AR_ELEMENT: + array_ref = NULL; + 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) + { + /* F03:C614. */ + if (ref->u.c.component->attr.pointer + || ref->u.c.component->attr.proc_pointer + || (ref->u.c.component->ts.type == BT_CLASS + && CLASS_DATA (ref->u.c.component)->attr.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 false; + } + else if (ref->u.c.component->attr.allocatable + || (ref->u.c.component->ts.type == BT_CLASS + && CLASS_DATA (ref->u.c.component)->attr.allocatable)) + + { + gfc_error ("Component to the right of a part reference " + "with nonzero rank must not have the ALLOCATABLE " + "attribute at %L", &expr->where); + return false; + } + } + + n_components++; + break; + + case REF_SUBSTRING: + break; + + case REF_INQUIRY: + /* Implement requirement in note 9.7 of F2018 that the result of the + LEN inquiry be a scalar. */ + if (ref->u.i == INQUIRY_LEN && array_ref && expr->ts.deferred) + { + array_ref->u.ar.type = AR_ELEMENT; + expr->rank = 0; + /* INQUIRY_LEN is not evaluated from the rest of the expr + but directly from the string length. This means that setting + the array indices to one does not matter but might trigger + a runtime bounds error. Suppress the check. */ + expr->no_bounds_check = 1; + for (dim = 0; dim < array_ref->u.ar.dimen; dim++) + { + array_ref->u.ar.dimen_type[dim] = DIMEN_ELEMENT; + if (array_ref->u.ar.start[dim]) + gfc_free_expr (array_ref->u.ar.start[dim]); + array_ref->u.ar.start[dim] + = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1); + if (array_ref->u.ar.end[dim]) + gfc_free_expr (array_ref->u.ar.end[dim]); + if (array_ref->u.ar.stride[dim]) + gfc_free_expr (array_ref->u.ar.stride[dim]); + } + } + 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 false; + } + + if (ref->type == REF_COMPONENT) + { + if (current_part_dimension) + seen_part_dimension = 1; + + /* reset to make sure */ + current_part_dimension = 0; + } + } + + return true; +} + + +/* 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])) + 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. */ + +void +gfc_expression_rank (gfc_expr *e) +{ + gfc_ref *ref; + int i, rank; + + /* Just to make sure, because EXPR_COMPCALL's also have an e->ref and that + could lead to serious confusion... */ + gcc_assert (e->expr_type != EXPR_COMPCALL); + + if (e->ref == NULL) + { + if (e->expr_type == EXPR_ARRAY) + goto done; + /* Constructors can have a rank different from one via RESHAPE(). */ + + e->rank = ((e->symtree == NULL || 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_COMPONENT && ref->u.c.component->attr.proc_pointer + && ref->u.c.component->attr.function && !ref->next) + rank = ref->u.c.component->as ? ref->u.c.component->as->rank : 0; + + 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 ("gfc_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); +} + + +static void +add_caf_get_intrinsic (gfc_expr *e) +{ + gfc_expr *wrapper, *tmp_expr; + gfc_ref *ref; + int n; + + for (ref = e->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0) + break; + if (ref == NULL) + return; + + for (n = ref->u.ar.dimen; n < ref->u.ar.dimen + ref->u.ar.codimen; n++) + if (ref->u.ar.dimen_type[n] != DIMEN_ELEMENT) + return; + + tmp_expr = XCNEW (gfc_expr); + *tmp_expr = *e; + wrapper = gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_CAF_GET, + "caf_get", tmp_expr->where, 1, tmp_expr); + wrapper->ts = e->ts; + wrapper->rank = e->rank; + if (e->rank) + wrapper->shape = gfc_copy_shape (e->shape, e->rank); + *e = *wrapper; + free (wrapper); +} + + +static void +remove_caf_get_intrinsic (gfc_expr *e) +{ + gcc_assert (e->expr_type == EXPR_FUNCTION && e->value.function.isym + && e->value.function.isym->id == GFC_ISYM_CAF_GET); + gfc_expr *e2 = e->value.function.actual->expr; + e->value.function.actual->expr = NULL; + gfc_free_actual_arglist (e->value.function.actual); + gfc_free_shape (&e->shape, e->rank); + *e = *e2; + free (e2); +} + + +/* Resolve a variable expression. */ + +static bool +resolve_variable (gfc_expr *e) +{ + gfc_symbol *sym; + bool t; + + t = true; + + if (e->symtree == NULL) + return false; + sym = e->symtree->n.sym; + + /* Use same check as for TYPE(*) below; this check has to be before TYPE(*) + as ts.type is set to BT_ASSUMED in resolve_symbol. */ + if (sym->attr.ext_attr & (1 << EXT_ATTR_NO_ARG_CHECK)) + { + if (!actual_arg || inquiry_argument) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute may only " + "be used as actual argument", sym->name, &e->where); + return false; + } + } + /* TS 29113, 407b. */ + else if (e->ts.type == BT_ASSUMED) + { + if (!actual_arg) + { + gfc_error ("Assumed-type variable %s at %L may only be used " + "as actual argument", sym->name, &e->where); + return false; + } + else if (inquiry_argument && !first_actual_arg) + { + /* FIXME: It doesn't work reliably as inquiry_argument is not set + for all inquiry functions in resolve_function; the reason is + that the function-name resolution happens too late in that + function. */ + gfc_error ("Assumed-type variable %s at %L as actual argument to " + "an inquiry function shall be the first argument", + sym->name, &e->where); + return false; + } + } + /* TS 29113, C535b. */ + else if (((sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym) + && CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || (sym->ts.type != BT_CLASS && sym->as + && sym->as->type == AS_ASSUMED_RANK)) + && !sym->attr.select_rank_temporary) + { + if (!actual_arg + && !(cs_base && cs_base->current + && cs_base->current->op == EXEC_SELECT_RANK)) + { + gfc_error ("Assumed-rank variable %s at %L may only be used as " + "actual argument", sym->name, &e->where); + return false; + } + else if (inquiry_argument && !first_actual_arg) + { + /* FIXME: It doesn't work reliably as inquiry_argument is not set + for all inquiry functions in resolve_function; the reason is + that the function-name resolution happens too late in that + function. */ + gfc_error ("Assumed-rank variable %s at %L as actual argument " + "to an inquiry function shall be the first argument", + sym->name, &e->where); + return false; + } + } + + if ((sym->attr.ext_attr & (1 << EXT_ATTR_NO_ARG_CHECK)) && e->ref + && !(e->ref->type == REF_ARRAY && e->ref->u.ar.type == AR_FULL + && e->ref->next == NULL)) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute shall not have " + "a subobject reference", sym->name, &e->ref->u.ar.where); + return false; + } + /* TS 29113, 407b. */ + else if (e->ts.type == BT_ASSUMED && e->ref + && !(e->ref->type == REF_ARRAY && e->ref->u.ar.type == AR_FULL + && e->ref->next == NULL)) + { + gfc_error ("Assumed-type variable %s at %L shall not have a subobject " + "reference", sym->name, &e->ref->u.ar.where); + return false; + } + + /* TS 29113, C535b. */ + if (((sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym) + && CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || (sym->ts.type != BT_CLASS && sym->as + && sym->as->type == AS_ASSUMED_RANK)) + && e->ref + && !(e->ref->type == REF_ARRAY && e->ref->u.ar.type == AR_FULL + && e->ref->next == NULL)) + { + gfc_error ("Assumed-rank variable %s at %L shall not have a subobject " + "reference", sym->name, &e->ref->u.ar.where); + return false; + } + + /* For variables that are used in an associate (target => object) where + the object's basetype is array valued while the target is scalar, + the ts' type of the component refs is still array valued, which + can't be translated that way. */ + if (sym->assoc && e->rank == 0 && e->ref && sym->ts.type == BT_CLASS + && sym->assoc->target && sym->assoc->target->ts.type == BT_CLASS + && sym->assoc->target->ts.u.derived + && CLASS_DATA (sym->assoc->target) + && CLASS_DATA (sym->assoc->target)->as) + { + gfc_ref *ref = e->ref; + while (ref) + { + switch (ref->type) + { + case REF_COMPONENT: + ref->u.c.sym = sym->ts.u.derived; + /* Stop the loop. */ + ref = NULL; + break; + default: + ref = ref->next; + break; + } + } + } + + /* If this is an associate-name, it may be parsed with an array reference + in error even though the target is scalar. Fail directly in this case. + TODO Understand why class scalar expressions must be excluded. */ + if (sym->assoc && !(sym->ts.type == BT_CLASS && e->rank == 0)) + { + if (sym->ts.type == BT_CLASS) + gfc_fix_class_refs (e); + if (!sym->attr.dimension && e->ref && e->ref->type == REF_ARRAY) + return false; + else if (sym->attr.dimension && (!e->ref || e->ref->type != REF_ARRAY)) + { + /* This can happen because the parser did not detect that the + associate name is an array and the expression had no array + part_ref. */ + gfc_ref *ref = gfc_get_ref (); + ref->type = REF_ARRAY; + ref->u.ar.type = AR_FULL; + if (sym->as) + { + ref->u.ar.as = sym->as; + ref->u.ar.dimen = sym->as->rank; + } + ref->next = e->ref; + e->ref = ref; + + } + } + + if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.generic) + sym->ts.u.derived = gfc_find_dt_in_generic (sym->ts.u.derived); + + /* On the other hand, the parser may not have known this is an array; + in this case, we have to add a FULL reference. */ + if (sym->assoc && sym->attr.dimension && !e->ref) + { + e->ref = gfc_get_ref (); + e->ref->type = REF_ARRAY; + e->ref->u.ar.type = AR_FULL; + e->ref->u.ar.dimen = 0; + } + + /* Like above, but for class types, where the checking whether an array + ref is present is more complicated. Furthermore make sure not to add + the full array ref to _vptr or _len refs. */ + if (sym->assoc && sym->ts.type == BT_CLASS && sym->ts.u.derived + && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.dimension + && (e->ts.type != BT_DERIVED || !e->ts.u.derived->attr.vtype)) + { + gfc_ref *ref, *newref; + + newref = gfc_get_ref (); + newref->type = REF_ARRAY; + newref->u.ar.type = AR_FULL; + newref->u.ar.dimen = 0; + /* Because this is an associate var and the first ref either is a ref to + the _data component or not, no traversal of the ref chain is + needed. The array ref needs to be inserted after the _data ref, + or when that is not present, which may happend for polymorphic + types, then at the first position. */ + ref = e->ref; + if (!ref) + e->ref = newref; + else if (ref->type == REF_COMPONENT + && strcmp ("_data", ref->u.c.component->name) == 0) + { + if (!ref->next || ref->next->type != REF_ARRAY) + { + newref->next = ref->next; + ref->next = newref; + } + else + /* Array ref present already. */ + gfc_free_ref_list (newref); + } + else if (ref->type == REF_ARRAY) + /* Array ref present already. */ + gfc_free_ref_list (newref); + else + { + newref->next = ref; + e->ref = newref; + } + } + + if (e->ref && !gfc_resolve_ref (e)) + return false; + + if (sym->attr.flavor == FL_PROCEDURE + && (!sym->attr.function + || (sym->attr.function && sym->result + && sym->result->attr.proc_pointer + && !sym->result->attr.function))) + { + e->ts.type = BT_PROCEDURE; + goto resolve_procedure; + } + + if (sym->ts.type != BT_UNKNOWN) + gfc_variable_attr (e, &e->ts); + else if (sym->attr.flavor == FL_PROCEDURE + && sym->attr.function && sym->result + && sym->result->ts.type != BT_UNKNOWN + && sym->result->attr.proc_pointer) + e->ts = sym->result->ts; + else + { + /* Must be a simple variable reference. */ + if (!gfc_set_default_type (sym, 1, sym->ns)) + return false; + e->ts = sym->ts; + } + + if (check_assumed_size_reference (sym, e)) + return false; + + /* Deal with forward references to entries during gfc_resolve_code, to + satisfy, at least partially, 12.5.2.5. */ + if (gfc_current_ns->entries + && current_entry_id == sym->entry_id + && cs_base + && cs_base->current + && cs_base->current->op != EXEC_ENTRY) + { + gfc_entry_list *entry; + gfc_formal_arglist *formal; + int n; + bool seen, saved_specification_expr; + + /* If the symbol is a dummy... */ + if (sym->attr.dummy && sym->ns == gfc_current_ns) + { + entry = gfc_current_ns->entries; + seen = false; + + /* ...test if the symbol is a parameter of previous entries. */ + for (; entry && entry->id <= current_entry_id; entry = entry->next) + for (formal = entry->sym->formal; formal; formal = formal->next) + { + if (formal->sym && sym->name == formal->sym->name) + { + seen = true; + break; + } + } + + /* If it has not been seen as a dummy, this is an error. */ + if (!seen) + { + if (specification_expr) + gfc_error ("Variable %qs, used in a specification expression" + ", is referenced at %L before the ENTRY statement " + "in which it is a parameter", + sym->name, &cs_base->current->loc); + else + gfc_error ("Variable %qs is used at %L before the ENTRY " + "statement in which it is a parameter", + sym->name, &cs_base->current->loc); + t = false; + } + } + + /* Now do the same check on the specification expressions. */ + saved_specification_expr = specification_expr; + specification_expr = true; + if (sym->ts.type == BT_CHARACTER + && !gfc_resolve_expr (sym->ts.u.cl->length)) + t = false; + + if (sym->as) + for (n = 0; n < sym->as->rank; n++) + { + if (!gfc_resolve_expr (sym->as->lower[n])) + t = false; + if (!gfc_resolve_expr (sym->as->upper[n])) + t = false; + } + specification_expr = saved_specification_expr; + + if (t) + /* Update the symbol's entry level. */ + sym->entry_id = current_entry_id + 1; + } + + /* If a symbol has been host_associated mark it. This is used latter, + to identify if aliasing is possible via host association. */ + if (sym->attr.flavor == FL_VARIABLE + && gfc_current_ns->parent + && (gfc_current_ns->parent == sym->ns + || (gfc_current_ns->parent->parent + && gfc_current_ns->parent->parent == sym->ns))) + sym->attr.host_assoc = 1; + + if (gfc_current_ns->proc_name + && sym->attr.dimension + && (sym->ns != gfc_current_ns + || sym->attr.use_assoc + || sym->attr.in_common)) + gfc_current_ns->proc_name->attr.array_outer_dependency = 1; + +resolve_procedure: + if (t && !resolve_procedure_expression (e)) + t = false; + + /* F2008, C617 and C1229. */ + if (!inquiry_argument && (e->ts.type == BT_CLASS || e->ts.type == BT_DERIVED) + && gfc_is_coindexed (e)) + { + gfc_ref *ref, *ref2 = NULL; + + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type == REF_COMPONENT) + ref2 = ref; + if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0) + break; + } + + for ( ; ref; ref = ref->next) + if (ref->type == REF_COMPONENT) + break; + + /* Expression itself is not coindexed object. */ + if (ref && e->ts.type == BT_CLASS) + { + gfc_error ("Polymorphic subobject of coindexed object at %L", + &e->where); + t = false; + } + + /* Expression itself is coindexed object. */ + if (ref == NULL) + { + gfc_component *c; + c = ref2 ? ref2->u.c.component : e->symtree->n.sym->components; + for ( ; c; c = c->next) + if (c->attr.allocatable && c->ts.type == BT_CLASS) + { + gfc_error ("Coindexed object with polymorphic allocatable " + "subcomponent at %L", &e->where); + t = false; + break; + } + } + } + + if (t) + gfc_expression_rank (e); + + if (t && flag_coarray == GFC_FCOARRAY_LIB && gfc_is_coindexed (e)) + add_caf_get_intrinsic (e); + + if (sym->attr.ext_attr & (1 << EXT_ATTR_DEPRECATED) && sym != sym->result) + gfc_warning (OPT_Wdeprecated_declarations, + "Using variable %qs at %L is deprecated", + sym->name, &e->where); + /* Simplify cases where access to a parameter array results in a + single constant. Suppress errors since those will have been + issued before, as warnings. */ + if (e->rank == 0 && sym->as && sym->attr.flavor == FL_PARAMETER) + { + gfc_push_suppress_errors (); + gfc_simplify_expr (e, 1); + gfc_pop_suppress_errors (); + } + + return t; +} + + +/* Checks to see that the correct symbol has been host associated. + The only situation where this arises is that in which a twice + contained function is parsed after the host association is made. + Therefore, on detecting this, change the symbol in the expression + and convert the array reference into an actual arglist if the old + symbol is a variable. */ +static bool +check_host_association (gfc_expr *e) +{ + gfc_symbol *sym, *old_sym; + gfc_symtree *st; + int n; + gfc_ref *ref; + gfc_actual_arglist *arg, *tail = NULL; + bool retval = e->expr_type == EXPR_FUNCTION; + + /* If the expression is the result of substitution in + interface.c(gfc_extend_expr) because there is no way in + which the host association can be wrong. */ + if (e->symtree == NULL + || e->symtree->n.sym == NULL + || e->user_operator) + return retval; + + old_sym = e->symtree->n.sym; + + if (gfc_current_ns->parent + && old_sym->ns != gfc_current_ns) + { + /* Use the 'USE' name so that renamed module symbols are + correctly handled. */ + gfc_find_symbol (e->symtree->name, gfc_current_ns, 1, &sym); + + if (sym && old_sym != sym + && sym->ts.type == old_sym->ts.type + && sym->attr.flavor == FL_PROCEDURE + && sym->attr.contained) + { + /* Clear the shape, since it might not be valid. */ + gfc_free_shape (&e->shape, e->rank); + + /* Give the expression the right symtree! */ + gfc_find_sym_tree (e->symtree->name, NULL, 1, &st); + gcc_assert (st != NULL); + + if (old_sym->attr.flavor == FL_PROCEDURE + || e->expr_type == EXPR_FUNCTION) + { + /* Original was function so point to the new symbol, since + the actual argument list is already attached to the + expression. */ + e->value.function.esym = NULL; + e->symtree = st; + } + else + { + /* Original was variable so convert array references into + an actual arglist. This does not need any checking now + since resolve_function will take care of it. */ + e->value.function.actual = NULL; + e->expr_type = EXPR_FUNCTION; + e->symtree = st; + + /* Ambiguity will not arise if the array reference is not + the last reference. */ + for (ref = e->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->next == NULL) + break; + + if ((ref == NULL || ref->type != REF_ARRAY) + && sym->attr.proc == PROC_INTERNAL) + { + gfc_error ("%qs at %L is host associated at %L into " + "a contained procedure with an internal " + "procedure of the same name", sym->name, + &old_sym->declared_at, &e->where); + return false; + } + + gcc_assert (ref->type == REF_ARRAY); + + /* Grab the start expressions from the array ref and + copy them into actual arguments. */ + for (n = 0; n < ref->u.ar.dimen; n++) + { + arg = gfc_get_actual_arglist (); + arg->expr = gfc_copy_expr (ref->u.ar.start[n]); + if (e->value.function.actual == NULL) + tail = e->value.function.actual = arg; + else + { + tail->next = arg; + tail = arg; + } + } + + /* Dump the reference list and set the rank. */ + gfc_free_ref_list (e->ref); + e->ref = NULL; + e->rank = sym->as ? sym->as->rank : 0; + } + + gfc_resolve_expr (e); + sym->refs++; + } + } + /* This might have changed! */ + return e->expr_type == EXPR_FUNCTION; +} + + +static void +gfc_resolve_character_operator (gfc_expr *e) +{ + gfc_expr *op1 = e->value.op.op1; + gfc_expr *op2 = e->value.op.op2; + gfc_expr *e1 = NULL; + gfc_expr *e2 = NULL; + + gcc_assert (e->value.op.op == INTRINSIC_CONCAT); + + if (op1->ts.u.cl && op1->ts.u.cl->length) + e1 = gfc_copy_expr (op1->ts.u.cl->length); + else if (op1->expr_type == EXPR_CONSTANT) + e1 = gfc_get_int_expr (gfc_charlen_int_kind, NULL, + op1->value.character.length); + + if (op2->ts.u.cl && op2->ts.u.cl->length) + e2 = gfc_copy_expr (op2->ts.u.cl->length); + else if (op2->expr_type == EXPR_CONSTANT) + e2 = gfc_get_int_expr (gfc_charlen_int_kind, NULL, + op2->value.character.length); + + e->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL); + + if (!e1 || !e2) + { + gfc_free_expr (e1); + gfc_free_expr (e2); + + return; + } + + e->ts.u.cl->length = gfc_add (e1, e2); + e->ts.u.cl->length->ts.type = BT_INTEGER; + e->ts.u.cl->length->ts.kind = gfc_charlen_int_kind; + gfc_simplify_expr (e->ts.u.cl->length, 0); + gfc_resolve_expr (e->ts.u.cl->length); + + return; +} + + +/* Ensure that an character expression has a charlen and, if possible, a + length expression. */ + +static void +fixup_charlen (gfc_expr *e) +{ + /* The cases fall through so that changes in expression type and the need + for multiple fixes are picked up. In all circumstances, a charlen should + be available for the middle end to hang a backend_decl on. */ + switch (e->expr_type) + { + case EXPR_OP: + gfc_resolve_character_operator (e); + /* FALLTHRU */ + + case EXPR_ARRAY: + if (e->expr_type == EXPR_ARRAY) + gfc_resolve_character_array_constructor (e); + /* FALLTHRU */ + + case EXPR_SUBSTRING: + if (!e->ts.u.cl && e->ref) + gfc_resolve_substring_charlen (e); + /* FALLTHRU */ + + default: + if (!e->ts.u.cl) + e->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL); + + break; + } +} + + +/* Update an actual argument to include the passed-object for type-bound + procedures at the right position. */ + +static gfc_actual_arglist* +update_arglist_pass (gfc_actual_arglist* lst, gfc_expr* po, unsigned argpos, + const char *name) +{ + gcc_assert (argpos > 0); + + if (argpos == 1) + { + gfc_actual_arglist* result; + + result = gfc_get_actual_arglist (); + result->expr = po; + result->next = lst; + if (name) + result->name = name; + + return result; + } + + if (lst) + lst->next = update_arglist_pass (lst->next, po, argpos - 1, name); + else + lst = update_arglist_pass (NULL, po, argpos - 1, name); + return lst; +} + + +/* Extract the passed-object from an EXPR_COMPCALL (a copy of it). */ + +static gfc_expr* +extract_compcall_passed_object (gfc_expr* e) +{ + gfc_expr* po; + + if (e->expr_type == EXPR_UNKNOWN) + { + gfc_error ("Error in typebound call at %L", + &e->where); + return NULL; + } + + gcc_assert (e->expr_type == EXPR_COMPCALL); + + if (e->value.compcall.base_object) + po = gfc_copy_expr (e->value.compcall.base_object); + else + { + po = gfc_get_expr (); + po->expr_type = EXPR_VARIABLE; + po->symtree = e->symtree; + po->ref = gfc_copy_ref (e->ref); + po->where = e->where; + } + + if (!gfc_resolve_expr (po)) + return NULL; + + return po; +} + + +/* Update the arglist of an EXPR_COMPCALL expression to include the + passed-object. */ + +static bool +update_compcall_arglist (gfc_expr* e) +{ + gfc_expr* po; + gfc_typebound_proc* tbp; + + tbp = e->value.compcall.tbp; + + if (tbp->error) + return false; + + po = extract_compcall_passed_object (e); + if (!po) + return false; + + if (tbp->nopass || e->value.compcall.ignore_pass) + { + gfc_free_expr (po); + return true; + } + + if (tbp->pass_arg_num <= 0) + return false; + + e->value.compcall.actual = update_arglist_pass (e->value.compcall.actual, po, + tbp->pass_arg_num, + tbp->pass_arg); + + return true; +} + + +/* Extract the passed object from a PPC call (a copy of it). */ + +static gfc_expr* +extract_ppc_passed_object (gfc_expr *e) +{ + gfc_expr *po; + gfc_ref **ref; + + po = gfc_get_expr (); + po->expr_type = EXPR_VARIABLE; + po->symtree = e->symtree; + po->ref = gfc_copy_ref (e->ref); + po->where = e->where; + + /* Remove PPC reference. */ + ref = &po->ref; + while ((*ref)->next) + ref = &(*ref)->next; + gfc_free_ref_list (*ref); + *ref = NULL; + + if (!gfc_resolve_expr (po)) + return NULL; + + return po; +} + + +/* Update the actual arglist of a procedure pointer component to include the + passed-object. */ + +static bool +update_ppc_arglist (gfc_expr* e) +{ + gfc_expr* po; + gfc_component *ppc; + gfc_typebound_proc* tb; + + ppc = gfc_get_proc_ptr_comp (e); + if (!ppc) + return false; + + tb = ppc->tb; + + if (tb->error) + return false; + else if (tb->nopass) + return true; + + po = extract_ppc_passed_object (e); + if (!po) + return false; + + /* F08:R739. */ + if (po->rank != 0) + { + gfc_error ("Passed-object at %L must be scalar", &e->where); + return false; + } + + /* F08:C611. */ + if (po->ts.type == BT_DERIVED && po->ts.u.derived->attr.abstract) + { + gfc_error ("Base object for procedure-pointer component call at %L is of" + " ABSTRACT type %qs", &e->where, po->ts.u.derived->name); + return false; + } + + gcc_assert (tb->pass_arg_num > 0); + e->value.compcall.actual = update_arglist_pass (e->value.compcall.actual, po, + tb->pass_arg_num, + tb->pass_arg); + + return true; +} + + +/* Check that the object a TBP is called on is valid, i.e. it must not be + of ABSTRACT type (as in subobject%abstract_parent%tbp()). */ + +static bool +check_typebound_baseobject (gfc_expr* e) +{ + gfc_expr* base; + bool return_value = false; + + base = extract_compcall_passed_object (e); + if (!base) + return false; + + if (base->ts.type != BT_DERIVED && base->ts.type != BT_CLASS) + { + gfc_error ("Error in typebound call at %L", &e->where); + goto cleanup; + } + + if (base->ts.type == BT_CLASS && !gfc_expr_attr (base).class_ok) + return false; + + /* F08:C611. */ + if (base->ts.type == BT_DERIVED && base->ts.u.derived->attr.abstract) + { + gfc_error ("Base object for type-bound procedure call at %L is of" + " ABSTRACT type %qs", &e->where, base->ts.u.derived->name); + goto cleanup; + } + + /* F08:C1230. If the procedure called is NOPASS, + the base object must be scalar. */ + if (e->value.compcall.tbp->nopass && base->rank != 0) + { + gfc_error ("Base object for NOPASS type-bound procedure call at %L must" + " be scalar", &e->where); + goto cleanup; + } + + return_value = true; + +cleanup: + gfc_free_expr (base); + return return_value; +} + + +/* Resolve a call to a type-bound procedure, either function or subroutine, + statically from the data in an EXPR_COMPCALL expression. The adapted + arglist and the target-procedure symtree are returned. */ + +static bool +resolve_typebound_static (gfc_expr* e, gfc_symtree** target, + gfc_actual_arglist** actual) +{ + gcc_assert (e->expr_type == EXPR_COMPCALL); + gcc_assert (!e->value.compcall.tbp->is_generic); + + /* Update the actual arglist for PASS. */ + if (!update_compcall_arglist (e)) + return false; + + *actual = e->value.compcall.actual; + *target = e->value.compcall.tbp->u.specific; + + gfc_free_ref_list (e->ref); + e->ref = NULL; + e->value.compcall.actual = NULL; + + /* If we find a deferred typebound procedure, check for derived types + that an overriding typebound procedure has not been missed. */ + if (e->value.compcall.name + && !e->value.compcall.tbp->non_overridable + && e->value.compcall.base_object + && e->value.compcall.base_object->ts.type == BT_DERIVED) + { + gfc_symtree *st; + gfc_symbol *derived; + + /* Use the derived type of the base_object. */ + derived = e->value.compcall.base_object->ts.u.derived; + st = NULL; + + /* If necessary, go through the inheritance chain. */ + while (!st && derived) + { + /* Look for the typebound procedure 'name'. */ + if (derived->f2k_derived && derived->f2k_derived->tb_sym_root) + st = gfc_find_symtree (derived->f2k_derived->tb_sym_root, + e->value.compcall.name); + if (!st) + derived = gfc_get_derived_super_type (derived); + } + + /* Now find the specific name in the derived type namespace. */ + if (st && st->n.tb && st->n.tb->u.specific) + gfc_find_sym_tree (st->n.tb->u.specific->name, + derived->ns, 1, &st); + if (st) + *target = st; + } + return true; +} + + +/* Get the ultimate declared type from an expression. In addition, + return the last class/derived type reference and the copy of the + reference list. If check_types is set true, derived types are + identified as well as class references. */ +static gfc_symbol* +get_declared_from_expr (gfc_ref **class_ref, gfc_ref **new_ref, + gfc_expr *e, bool check_types) +{ + gfc_symbol *declared; + gfc_ref *ref; + + declared = NULL; + if (class_ref) + *class_ref = NULL; + if (new_ref) + *new_ref = gfc_copy_ref (e->ref); + + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type != REF_COMPONENT) + continue; + + if ((ref->u.c.component->ts.type == BT_CLASS + || (check_types && gfc_bt_struct (ref->u.c.component->ts.type))) + && ref->u.c.component->attr.flavor != FL_PROCEDURE) + { + declared = ref->u.c.component->ts.u.derived; + if (class_ref) + *class_ref = ref; + } + } + + if (declared == NULL) + declared = e->symtree->n.sym->ts.u.derived; + + return declared; +} + + +/* Given an EXPR_COMPCALL calling a GENERIC typebound procedure, figure out + which of the specific bindings (if any) matches the arglist and transform + the expression into a call of that binding. */ + +static bool +resolve_typebound_generic_call (gfc_expr* e, const char **name) +{ + gfc_typebound_proc* genproc; + const char* genname; + gfc_symtree *st; + gfc_symbol *derived; + + gcc_assert (e->expr_type == EXPR_COMPCALL); + genname = e->value.compcall.name; + genproc = e->value.compcall.tbp; + + if (!genproc->is_generic) + return true; + + /* Try the bindings on this type and in the inheritance hierarchy. */ + for (; genproc; genproc = genproc->overridden) + { + gfc_tbp_generic* g; + + gcc_assert (genproc->is_generic); + for (g = genproc->u.generic; g; g = g->next) + { + gfc_symbol* target; + gfc_actual_arglist* args; + bool matches; + + gcc_assert (g->specific); + + if (g->specific->error) + continue; + + target = g->specific->u.specific->n.sym; + + /* Get the right arglist by handling PASS/NOPASS. */ + args = gfc_copy_actual_arglist (e->value.compcall.actual); + if (!g->specific->nopass) + { + gfc_expr* po; + po = extract_compcall_passed_object (e); + if (!po) + { + gfc_free_actual_arglist (args); + return false; + } + + gcc_assert (g->specific->pass_arg_num > 0); + gcc_assert (!g->specific->error); + args = update_arglist_pass (args, po, g->specific->pass_arg_num, + g->specific->pass_arg); + } + resolve_actual_arglist (args, target->attr.proc, + is_external_proc (target) + && gfc_sym_get_dummy_args (target) == NULL); + + /* Check if this arglist matches the formal. */ + matches = gfc_arglist_matches_symbol (&args, target); + + /* Clean up and break out of the loop if we've found it. */ + gfc_free_actual_arglist (args); + if (matches) + { + e->value.compcall.tbp = g->specific; + genname = g->specific_st->name; + /* Pass along the name for CLASS methods, where the vtab + procedure pointer component has to be referenced. */ + if (name) + *name = genname; + goto success; + } + } + } + + /* Nothing matching found! */ + gfc_error ("Found no matching specific binding for the call to the GENERIC" + " %qs at %L", genname, &e->where); + return false; + +success: + /* Make sure that we have the right specific instance for the name. */ + derived = get_declared_from_expr (NULL, NULL, e, true); + + st = gfc_find_typebound_proc (derived, NULL, genname, true, &e->where); + if (st) + e->value.compcall.tbp = st->n.tb; + + return true; +} + + +/* Resolve a call to a type-bound subroutine. */ + +static bool +resolve_typebound_call (gfc_code* c, const char **name, bool *overridable) +{ + gfc_actual_arglist* newactual; + gfc_symtree* target; + + /* Check that's really a SUBROUTINE. */ + if (!c->expr1->value.compcall.tbp->subroutine) + { + if (!c->expr1->value.compcall.tbp->is_generic + && c->expr1->value.compcall.tbp->u.specific + && c->expr1->value.compcall.tbp->u.specific->n.sym + && c->expr1->value.compcall.tbp->u.specific->n.sym->attr.subroutine) + c->expr1->value.compcall.tbp->subroutine = 1; + else + { + gfc_error ("%qs at %L should be a SUBROUTINE", + c->expr1->value.compcall.name, &c->loc); + return false; + } + } + + if (!check_typebound_baseobject (c->expr1)) + return false; + + /* Pass along the name for CLASS methods, where the vtab + procedure pointer component has to be referenced. */ + if (name) + *name = c->expr1->value.compcall.name; + + if (!resolve_typebound_generic_call (c->expr1, name)) + return false; + + /* Pass along the NON_OVERRIDABLE attribute of the specific TBP. */ + if (overridable) + *overridable = !c->expr1->value.compcall.tbp->non_overridable; + + /* Transform into an ordinary EXEC_CALL for now. */ + + if (!resolve_typebound_static (c->expr1, &target, &newactual)) + return false; + + c->ext.actual = newactual; + c->symtree = target; + c->op = (c->expr1->value.compcall.assign ? EXEC_ASSIGN_CALL : EXEC_CALL); + + gcc_assert (!c->expr1->ref && !c->expr1->value.compcall.actual); + + gfc_free_expr (c->expr1); + c->expr1 = gfc_get_expr (); + c->expr1->expr_type = EXPR_FUNCTION; + c->expr1->symtree = target; + c->expr1->where = c->loc; + + return resolve_call (c); +} + + +/* Resolve a component-call expression. */ +static bool +resolve_compcall (gfc_expr* e, const char **name) +{ + gfc_actual_arglist* newactual; + gfc_symtree* target; + + /* Check that's really a FUNCTION. */ + if (!e->value.compcall.tbp->function) + { + gfc_error ("%qs at %L should be a FUNCTION", + e->value.compcall.name, &e->where); + return false; + } + + + /* These must not be assign-calls! */ + gcc_assert (!e->value.compcall.assign); + + if (!check_typebound_baseobject (e)) + return false; + + /* Pass along the name for CLASS methods, where the vtab + procedure pointer component has to be referenced. */ + if (name) + *name = e->value.compcall.name; + + if (!resolve_typebound_generic_call (e, name)) + return false; + gcc_assert (!e->value.compcall.tbp->is_generic); + + /* Take the rank from the function's symbol. */ + if (e->value.compcall.tbp->u.specific->n.sym->as) + e->rank = e->value.compcall.tbp->u.specific->n.sym->as->rank; + + /* For now, we simply transform it into an EXPR_FUNCTION call with the same + arglist to the TBP's binding target. */ + + if (!resolve_typebound_static (e, &target, &newactual)) + return false; + + e->value.function.actual = newactual; + e->value.function.name = NULL; + e->value.function.esym = target->n.sym; + e->value.function.isym = NULL; + e->symtree = target; + e->ts = target->n.sym->ts; + e->expr_type = EXPR_FUNCTION; + + /* Resolution is not necessary if this is a class subroutine; this + function only has to identify the specific proc. Resolution of + the call will be done next in resolve_typebound_call. */ + return gfc_resolve_expr (e); +} + + +static bool resolve_fl_derived (gfc_symbol *sym); + + +/* Resolve a typebound function, or 'method'. First separate all + the non-CLASS references by calling resolve_compcall directly. */ + +static bool +resolve_typebound_function (gfc_expr* e) +{ + gfc_symbol *declared; + gfc_component *c; + gfc_ref *new_ref; + gfc_ref *class_ref; + gfc_symtree *st; + const char *name; + gfc_typespec ts; + gfc_expr *expr; + bool overridable; + + st = e->symtree; + + /* Deal with typebound operators for CLASS objects. */ + expr = e->value.compcall.base_object; + overridable = !e->value.compcall.tbp->non_overridable; + if (expr && expr->ts.type == BT_CLASS && e->value.compcall.name) + { + /* Since the typebound operators are generic, we have to ensure + that any delays in resolution are corrected and that the vtab + is present. */ + ts = expr->ts; + declared = ts.u.derived; + c = gfc_find_component (declared, "_vptr", true, true, NULL); + if (c->ts.u.derived == NULL) + c->ts.u.derived = gfc_find_derived_vtab (declared); + + if (!resolve_compcall (e, &name)) + return false; + + /* Use the generic name if it is there. */ + name = name ? name : e->value.function.esym->name; + e->symtree = expr->symtree; + e->ref = gfc_copy_ref (expr->ref); + get_declared_from_expr (&class_ref, NULL, e, false); + + /* Trim away the extraneous references that emerge from nested + use of interface.c (extend_expr). */ + if (class_ref && class_ref->next) + { + gfc_free_ref_list (class_ref->next); + class_ref->next = NULL; + } + else if (e->ref && !class_ref && expr->ts.type != BT_CLASS) + { + gfc_free_ref_list (e->ref); + e->ref = NULL; + } + + gfc_add_vptr_component (e); + gfc_add_component_ref (e, name); + e->value.function.esym = NULL; + if (expr->expr_type != EXPR_VARIABLE) + e->base_expr = expr; + return true; + } + + if (st == NULL) + return resolve_compcall (e, NULL); + + if (!gfc_resolve_ref (e)) + return false; + + /* Get the CLASS declared type. */ + declared = get_declared_from_expr (&class_ref, &new_ref, e, true); + + if (!resolve_fl_derived (declared)) + return false; + + /* Weed out cases of the ultimate component being a derived type. */ + if ((class_ref && gfc_bt_struct (class_ref->u.c.component->ts.type)) + || (!class_ref && st->n.sym->ts.type != BT_CLASS)) + { + gfc_free_ref_list (new_ref); + return resolve_compcall (e, NULL); + } + + c = gfc_find_component (declared, "_data", true, true, NULL); + + /* Treat the call as if it is a typebound procedure, in order to roll + out the correct name for the specific function. */ + if (!resolve_compcall (e, &name)) + { + gfc_free_ref_list (new_ref); + return false; + } + ts = e->ts; + + if (overridable) + { + /* Convert the expression to a procedure pointer component call. */ + e->value.function.esym = NULL; + e->symtree = st; + + if (new_ref) + e->ref = new_ref; + + /* '_vptr' points to the vtab, which contains the procedure pointers. */ + gfc_add_vptr_component (e); + gfc_add_component_ref (e, name); + + /* Recover the typespec for the expression. This is really only + necessary for generic procedures, where the additional call + to gfc_add_component_ref seems to throw the collection of the + correct typespec. */ + e->ts = ts; + } + else if (new_ref) + gfc_free_ref_list (new_ref); + + return true; +} + +/* Resolve a typebound subroutine, or 'method'. First separate all + the non-CLASS references by calling resolve_typebound_call + directly. */ + +static bool +resolve_typebound_subroutine (gfc_code *code) +{ + gfc_symbol *declared; + gfc_component *c; + gfc_ref *new_ref; + gfc_ref *class_ref; + gfc_symtree *st; + const char *name; + gfc_typespec ts; + gfc_expr *expr; + bool overridable; + + st = code->expr1->symtree; + + /* Deal with typebound operators for CLASS objects. */ + expr = code->expr1->value.compcall.base_object; + overridable = !code->expr1->value.compcall.tbp->non_overridable; + if (expr && expr->ts.type == BT_CLASS && code->expr1->value.compcall.name) + { + /* If the base_object is not a variable, the corresponding actual + argument expression must be stored in e->base_expression so + that the corresponding tree temporary can be used as the base + object in gfc_conv_procedure_call. */ + if (expr->expr_type != EXPR_VARIABLE) + { + gfc_actual_arglist *args; + + args= code->expr1->value.function.actual; + for (; args; args = args->next) + if (expr == args->expr) + expr = args->expr; + } + + /* Since the typebound operators are generic, we have to ensure + that any delays in resolution are corrected and that the vtab + is present. */ + declared = expr->ts.u.derived; + c = gfc_find_component (declared, "_vptr", true, true, NULL); + if (c->ts.u.derived == NULL) + c->ts.u.derived = gfc_find_derived_vtab (declared); + + if (!resolve_typebound_call (code, &name, NULL)) + return false; + + /* Use the generic name if it is there. */ + name = name ? name : code->expr1->value.function.esym->name; + code->expr1->symtree = expr->symtree; + code->expr1->ref = gfc_copy_ref (expr->ref); + + /* Trim away the extraneous references that emerge from nested + use of interface.c (extend_expr). */ + get_declared_from_expr (&class_ref, NULL, code->expr1, false); + if (class_ref && class_ref->next) + { + gfc_free_ref_list (class_ref->next); + class_ref->next = NULL; + } + else if (code->expr1->ref && !class_ref) + { + gfc_free_ref_list (code->expr1->ref); + code->expr1->ref = NULL; + } + + /* Now use the procedure in the vtable. */ + gfc_add_vptr_component (code->expr1); + gfc_add_component_ref (code->expr1, name); + code->expr1->value.function.esym = NULL; + if (expr->expr_type != EXPR_VARIABLE) + code->expr1->base_expr = expr; + return true; + } + + if (st == NULL) + return resolve_typebound_call (code, NULL, NULL); + + if (!gfc_resolve_ref (code->expr1)) + return false; + + /* Get the CLASS declared type. */ + get_declared_from_expr (&class_ref, &new_ref, code->expr1, true); + + /* Weed out cases of the ultimate component being a derived type. */ + if ((class_ref && gfc_bt_struct (class_ref->u.c.component->ts.type)) + || (!class_ref && st->n.sym->ts.type != BT_CLASS)) + { + gfc_free_ref_list (new_ref); + return resolve_typebound_call (code, NULL, NULL); + } + + if (!resolve_typebound_call (code, &name, &overridable)) + { + gfc_free_ref_list (new_ref); + return false; + } + ts = code->expr1->ts; + + if (overridable) + { + /* Convert the expression to a procedure pointer component call. */ + code->expr1->value.function.esym = NULL; + code->expr1->symtree = st; + + if (new_ref) + code->expr1->ref = new_ref; + + /* '_vptr' points to the vtab, which contains the procedure pointers. */ + gfc_add_vptr_component (code->expr1); + gfc_add_component_ref (code->expr1, name); + + /* Recover the typespec for the expression. This is really only + necessary for generic procedures, where the additional call + to gfc_add_component_ref seems to throw the collection of the + correct typespec. */ + code->expr1->ts = ts; + } + else if (new_ref) + gfc_free_ref_list (new_ref); + + return true; +} + + +/* Resolve a CALL to a Procedure Pointer Component (Subroutine). */ + +static bool +resolve_ppc_call (gfc_code* c) +{ + gfc_component *comp; + + comp = gfc_get_proc_ptr_comp (c->expr1); + gcc_assert (comp != NULL); + + c->resolved_sym = c->expr1->symtree->n.sym; + c->expr1->expr_type = EXPR_VARIABLE; + + if (!comp->attr.subroutine) + gfc_add_subroutine (&comp->attr, comp->name, &c->expr1->where); + + if (!gfc_resolve_ref (c->expr1)) + return false; + + if (!update_ppc_arglist (c->expr1)) + return false; + + c->ext.actual = c->expr1->value.compcall.actual; + + if (!resolve_actual_arglist (c->ext.actual, comp->attr.proc, + !(comp->ts.interface + && comp->ts.interface->formal))) + return false; + + if (!pure_subroutine (comp->ts.interface, comp->name, &c->expr1->where)) + return false; + + gfc_ppc_use (comp, &c->expr1->value.compcall.actual, &c->expr1->where); + + return true; +} + + +/* Resolve a Function Call to a Procedure Pointer Component (Function). */ + +static bool +resolve_expr_ppc (gfc_expr* e) +{ + gfc_component *comp; + + comp = gfc_get_proc_ptr_comp (e); + gcc_assert (comp != NULL); + + /* Convert to EXPR_FUNCTION. */ + e->expr_type = EXPR_FUNCTION; + e->value.function.isym = NULL; + e->value.function.actual = e->value.compcall.actual; + e->ts = comp->ts; + if (comp->as != NULL) + e->rank = comp->as->rank; + + if (!comp->attr.function) + gfc_add_function (&comp->attr, comp->name, &e->where); + + if (!gfc_resolve_ref (e)) + return false; + + if (!resolve_actual_arglist (e->value.function.actual, comp->attr.proc, + !(comp->ts.interface + && comp->ts.interface->formal))) + return false; + + if (!update_ppc_arglist (e)) + return false; + + if (!check_pure_function(e)) + return false; + + gfc_ppc_use (comp, &e->value.compcall.actual, &e->where); + + return true; +} + + +static bool +gfc_is_expandable_expr (gfc_expr *e) +{ + gfc_constructor *con; + + if (e->expr_type == EXPR_ARRAY) + { + /* Traverse the constructor looking for variables that are flavor + parameter. Parameters must be expanded since they are fully used at + compile time. */ + con = gfc_constructor_first (e->value.constructor); + for (; con; con = gfc_constructor_next (con)) + { + if (con->expr->expr_type == EXPR_VARIABLE + && con->expr->symtree + && (con->expr->symtree->n.sym->attr.flavor == FL_PARAMETER + || con->expr->symtree->n.sym->attr.flavor == FL_VARIABLE)) + return true; + if (con->expr->expr_type == EXPR_ARRAY + && gfc_is_expandable_expr (con->expr)) + return true; + } + } + + return false; +} + + +/* Sometimes variables in specification expressions of the result + of module procedures in submodules wind up not being the 'real' + dummy. Find this, if possible, in the namespace of the first + formal argument. */ + +static void +fixup_unique_dummy (gfc_expr *e) +{ + gfc_symtree *st = NULL; + gfc_symbol *s = NULL; + + if (e->symtree->n.sym->ns->proc_name + && e->symtree->n.sym->ns->proc_name->formal) + s = e->symtree->n.sym->ns->proc_name->formal->sym; + + if (s != NULL) + st = gfc_find_symtree (s->ns->sym_root, e->symtree->n.sym->name); + + if (st != NULL + && st->n.sym != NULL + && st->n.sym->attr.dummy) + e->symtree = st; +} + +/* 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. */ + +bool +gfc_resolve_expr (gfc_expr *e) +{ + bool t; + bool inquiry_save, actual_arg_save, first_actual_arg_save; + + if (e == NULL || e->do_not_resolve_again) + return true; + + /* inquiry_argument only applies to variables. */ + inquiry_save = inquiry_argument; + actual_arg_save = actual_arg; + first_actual_arg_save = first_actual_arg; + + if (e->expr_type != EXPR_VARIABLE) + { + inquiry_argument = false; + actual_arg = false; + first_actual_arg = false; + } + else if (e->symtree != NULL + && *e->symtree->name == '@' + && e->symtree->n.sym->attr.dummy) + { + /* Deal with submodule specification expressions that are not + found to be referenced in module.c(read_cleanup). */ + fixup_unique_dummy (e); + } + + switch (e->expr_type) + { + case EXPR_OP: + t = resolve_operator (e); + break; + + case EXPR_FUNCTION: + case EXPR_VARIABLE: + + if (check_host_association (e)) + t = resolve_function (e); + else + t = resolve_variable (e); + + if (e->ts.type == BT_CHARACTER && e->ts.u.cl == NULL && e->ref + && e->ref->type != REF_SUBSTRING) + gfc_resolve_substring_charlen (e); + + break; + + case EXPR_COMPCALL: + t = resolve_typebound_function (e); + break; + + case EXPR_SUBSTRING: + t = gfc_resolve_ref (e); + break; + + case EXPR_CONSTANT: + case EXPR_NULL: + t = true; + break; + + case EXPR_PPC: + t = resolve_expr_ppc (e); + break; + + case EXPR_ARRAY: + t = false; + if (!gfc_resolve_ref (e)) + break; + + t = gfc_resolve_array_constructor (e); + /* Also try to expand a constructor. */ + if (t) + { + gfc_expression_rank (e); + if (gfc_is_constant_expr (e) || gfc_is_expandable_expr (e)) + gfc_expand_constructor (e, false); + } + + /* This provides the opportunity for the length of constructors with + character valued function elements to propagate the string length + to the expression. */ + if (t && e->ts.type == BT_CHARACTER) + { + /* For efficiency, we call gfc_expand_constructor for BT_CHARACTER + here rather then add a duplicate test for it above. */ + gfc_expand_constructor (e, false); + t = gfc_resolve_character_array_constructor (e); + } + + break; + + case EXPR_STRUCTURE: + t = gfc_resolve_ref (e); + if (!t) + break; + + t = resolve_structure_cons (e, 0); + if (!t) + break; + + t = gfc_simplify_expr (e, 0); + break; + + default: + gfc_internal_error ("gfc_resolve_expr(): Bad expression type"); + } + + if (e->ts.type == BT_CHARACTER && t && !e->ts.u.cl) + fixup_charlen (e); + + inquiry_argument = inquiry_save; + actual_arg = actual_arg_save; + first_actual_arg = first_actual_arg_save; + + /* For some reason, resolving these expressions a second time mangles + the typespec of the expression itself. */ + if (t && e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.select_rank_temporary + && UNLIMITED_POLY (e->symtree->n.sym)) + e->do_not_resolve_again = 1; + + return t; +} + + +/* Resolve an expression from an iterator. They must be scalar and have + INTEGER or (optionally) REAL type. */ + +static bool +gfc_resolve_iterator_expr (gfc_expr *expr, bool real_ok, + const char *name_msgid) +{ + if (!gfc_resolve_expr (expr)) + return false; + + if (expr->rank != 0) + { + gfc_error ("%s at %L must be a scalar", _(name_msgid), &expr->where); + return false; + } + + if (expr->ts.type != BT_INTEGER) + { + if (expr->ts.type == BT_REAL) + { + if (real_ok) + return gfc_notify_std (GFC_STD_F95_DEL, + "%s at %L must be integer", + _(name_msgid), &expr->where); + else + { + gfc_error ("%s at %L must be INTEGER", _(name_msgid), + &expr->where); + return false; + } + } + else + { + gfc_error ("%s at %L must be INTEGER", _(name_msgid), &expr->where); + return false; + } + } + return true; +} + + +/* Resolve the expressions in an iterator structure. If REAL_OK is + false allow only INTEGER type iterators, otherwise allow REAL types. + Set own_scope to true for ac-implied-do and data-implied-do as those + have a separate scope such that, e.g., a INTENT(IN) doesn't apply. */ + +bool +gfc_resolve_iterator (gfc_iterator *iter, bool real_ok, bool own_scope) +{ + if (!gfc_resolve_iterator_expr (iter->var, real_ok, "Loop variable")) + return false; + + if (!gfc_check_vardef_context (iter->var, false, false, own_scope, + _("iterator variable"))) + return false; + + if (!gfc_resolve_iterator_expr (iter->start, real_ok, + "Start expression in DO loop")) + return false; + + if (!gfc_resolve_iterator_expr (iter->end, real_ok, + "End expression in DO loop")) + return false; + + if (!gfc_resolve_iterator_expr (iter->step, real_ok, + "Step expression in DO loop")) + return false; + + /* Convert start, end, and step to the same type as var. */ + if (iter->start->ts.kind != iter->var->ts.kind + || iter->start->ts.type != iter->var->ts.type) + gfc_convert_type (iter->start, &iter->var->ts, 1); + + if (iter->end->ts.kind != iter->var->ts.kind + || iter->end->ts.type != iter->var->ts.type) + gfc_convert_type (iter->end, &iter->var->ts, 1); + + if (iter->step->ts.kind != iter->var->ts.kind + || iter->step->ts.type != iter->var->ts.type) + gfc_convert_type (iter->step, &iter->var->ts, 1); + + if (iter->step->expr_type == EXPR_CONSTANT) + { + if ((iter->step->ts.type == BT_INTEGER + && mpz_cmp_ui (iter->step->value.integer, 0) == 0) + || (iter->step->ts.type == BT_REAL + && mpfr_sgn (iter->step->value.real) == 0)) + { + gfc_error ("Step expression in DO loop at %L cannot be zero", + &iter->step->where); + return false; + } + } + + if (iter->start->expr_type == EXPR_CONSTANT + && iter->end->expr_type == EXPR_CONSTANT + && iter->step->expr_type == EXPR_CONSTANT) + { + int sgn, cmp; + if (iter->start->ts.type == BT_INTEGER) + { + sgn = mpz_cmp_ui (iter->step->value.integer, 0); + cmp = mpz_cmp (iter->end->value.integer, iter->start->value.integer); + } + else + { + sgn = mpfr_sgn (iter->step->value.real); + cmp = mpfr_cmp (iter->end->value.real, iter->start->value.real); + } + if (warn_zerotrip && ((sgn > 0 && cmp < 0) || (sgn < 0 && cmp > 0))) + gfc_warning (OPT_Wzerotrip, + "DO loop at %L will be executed zero times", + &iter->step->where); + } + + if (iter->end->expr_type == EXPR_CONSTANT + && iter->end->ts.type == BT_INTEGER + && iter->step->expr_type == EXPR_CONSTANT + && iter->step->ts.type == BT_INTEGER + && (mpz_cmp_si (iter->step->value.integer, -1L) == 0 + || mpz_cmp_si (iter->step->value.integer, 1L) == 0)) + { + bool is_step_positive = mpz_cmp_ui (iter->step->value.integer, 1) == 0; + int k = gfc_validate_kind (BT_INTEGER, iter->end->ts.kind, false); + + if (is_step_positive + && mpz_cmp (iter->end->value.integer, gfc_integer_kinds[k].huge) == 0) + gfc_warning (OPT_Wundefined_do_loop, + "DO loop at %L is undefined as it overflows", + &iter->step->where); + else if (!is_step_positive + && mpz_cmp (iter->end->value.integer, + gfc_integer_kinds[k].min_int) == 0) + gfc_warning (OPT_Wundefined_do_loop, + "DO loop at %L is undefined as it underflows", + &iter->step->where); + } + + return true; +} + + +/* Traversal function for find_forall_index. f == 2 signals that + that variable itself is not to be checked - only the references. */ + +static bool +forall_index (gfc_expr *expr, gfc_symbol *sym, int *f) +{ + if (expr->expr_type != EXPR_VARIABLE) + return false; + + /* A scalar assignment */ + if (!expr->ref || *f == 1) + { + if (expr->symtree->n.sym == sym) + return true; + else + return false; + } + + if (*f == 2) + *f = 1; + return false; +} + + +/* Check whether the FORALL index appears in the expression or not. + Returns true if SYM is found in EXPR. */ + +bool +find_forall_index (gfc_expr *expr, gfc_symbol *sym, int f) +{ + if (gfc_traverse_expr (expr, sym, forall_index, f)) + return true; + else + return false; +} + + +/* Resolve a list of FORALL iterators. The FORALL index-name is constrained + to be a scalar INTEGER variable. The subscripts and stride are scalar + INTEGERs, and if stride is a constant it must be nonzero. + Furthermore "A subscript or stride in a forall-triplet-spec shall + not contain a reference to any index-name in the + forall-triplet-spec-list in which it appears." (7.5.4.1) */ + +static void +resolve_forall_iterators (gfc_forall_iterator *it) +{ + gfc_forall_iterator *iter, *iter2; + + for (iter = it; iter; iter = iter->next) + { + if (gfc_resolve_expr (iter->var) + && (iter->var->ts.type != BT_INTEGER || iter->var->rank != 0)) + gfc_error ("FORALL index-name at %L must be a scalar INTEGER", + &iter->var->where); + + if (gfc_resolve_expr (iter->start) + && (iter->start->ts.type != BT_INTEGER || iter->start->rank != 0)) + gfc_error ("FORALL start expression at %L must be a scalar INTEGER", + &iter->start->where); + if (iter->var->ts.kind != iter->start->ts.kind) + gfc_convert_type (iter->start, &iter->var->ts, 1); + + if (gfc_resolve_expr (iter->end) + && (iter->end->ts.type != BT_INTEGER || iter->end->rank != 0)) + gfc_error ("FORALL end expression at %L must be a scalar INTEGER", + &iter->end->where); + if (iter->var->ts.kind != iter->end->ts.kind) + gfc_convert_type (iter->end, &iter->var->ts, 1); + + if (gfc_resolve_expr (iter->stride)) + { + if (iter->stride->ts.type != BT_INTEGER || iter->stride->rank != 0) + gfc_error ("FORALL stride expression at %L must be a scalar %s", + &iter->stride->where, "INTEGER"); + + if (iter->stride->expr_type == EXPR_CONSTANT + && mpz_cmp_ui (iter->stride->value.integer, 0) == 0) + gfc_error ("FORALL stride expression at %L cannot be zero", + &iter->stride->where); + } + if (iter->var->ts.kind != iter->stride->ts.kind) + gfc_convert_type (iter->stride, &iter->var->ts, 1); + } + + for (iter = it; iter; iter = iter->next) + for (iter2 = iter; iter2; iter2 = iter2->next) + { + if (find_forall_index (iter2->start, iter->var->symtree->n.sym, 0) + || find_forall_index (iter2->end, iter->var->symtree->n.sym, 0) + || find_forall_index (iter2->stride, iter->var->symtree->n.sym, 0)) + gfc_error ("FORALL index %qs may not appear in triplet " + "specification at %L", iter->var->symtree->name, + &iter2->start->where); + } +} + + +/* Given a pointer to a symbol that is a derived type, see if it's + inaccessible, i.e. if it's defined in another module and the components are + PRIVATE. The search is recursive if necessary. Returns zero if no + inaccessible components are found, nonzero otherwise. */ + +static int +derived_inaccessible (gfc_symbol *sym) +{ + gfc_component *c; + + if (sym->attr.use_assoc && sym->attr.private_comp) + return 1; + + for (c = sym->components; c; c = c->next) + { + /* Prevent an infinite loop through this function. */ + if (c->ts.type == BT_DERIVED && c->attr.pointer + && sym == c->ts.u.derived) + continue; + + if (c->ts.type == BT_DERIVED && derived_inaccessible (c->ts.u.derived)) + return 1; + } + + return 0; +} + + +/* Resolve the argument of a deallocate expression. The expression must be + a pointer or a full array. */ + +static bool +resolve_deallocate_expr (gfc_expr *e) +{ + symbol_attribute attr; + int allocatable, pointer; + gfc_ref *ref; + gfc_symbol *sym; + gfc_component *c; + bool unlimited; + + if (!gfc_resolve_expr (e)) + return false; + + if (e->expr_type != EXPR_VARIABLE) + goto bad; + + sym = e->symtree->n.sym; + unlimited = UNLIMITED_POLY(sym); + + if (sym->ts.type == BT_CLASS) + { + allocatable = CLASS_DATA (sym)->attr.allocatable; + pointer = CLASS_DATA (sym)->attr.class_pointer; + } + else + { + allocatable = sym->attr.allocatable; + pointer = sym->attr.pointer; + } + for (ref = e->ref; ref; ref = ref->next) + { + switch (ref->type) + { + case REF_ARRAY: + if (ref->u.ar.type != AR_FULL + && !(ref->u.ar.type == AR_ELEMENT && ref->u.ar.as->rank == 0 + && ref->u.ar.codimen && gfc_ref_this_image (ref))) + allocatable = 0; + break; + + case REF_COMPONENT: + c = ref->u.c.component; + if (c->ts.type == BT_CLASS) + { + allocatable = CLASS_DATA (c)->attr.allocatable; + pointer = CLASS_DATA (c)->attr.class_pointer; + } + else + { + allocatable = c->attr.allocatable; + pointer = c->attr.pointer; + } + break; + + case REF_SUBSTRING: + case REF_INQUIRY: + allocatable = 0; + break; + } + } + + attr = gfc_expr_attr (e); + + if (allocatable == 0 && attr.pointer == 0 && !unlimited) + { + bad: + gfc_error ("Allocate-object at %L must be ALLOCATABLE or a POINTER", + &e->where); + return false; + } + + /* F2008, C644. */ + if (gfc_is_coindexed (e)) + { + gfc_error ("Coindexed allocatable object at %L", &e->where); + return false; + } + + if (pointer + && !gfc_check_vardef_context (e, true, true, false, + _("DEALLOCATE object"))) + return false; + if (!gfc_check_vardef_context (e, false, true, false, + _("DEALLOCATE object"))) + return false; + + return true; +} + + +/* Returns true if the expression e contains a reference to the symbol sym. */ +static bool +sym_in_expr (gfc_expr *e, gfc_symbol *sym, int *f ATTRIBUTE_UNUSED) +{ + if (e->expr_type == EXPR_VARIABLE && e->symtree->n.sym == sym) + return true; + + return false; +} + +bool +gfc_find_sym_in_expr (gfc_symbol *sym, gfc_expr *e) +{ + return gfc_traverse_expr (e, sym, sym_in_expr, 0); +} + + +/* Given the expression node e for an allocatable/pointer of derived type to be + allocated, get the expression node to be initialized afterwards (needed for + derived types with default initializers, and derived types with allocatable + components that need nullification.) */ + +gfc_expr * +gfc_expr_to_initialize (gfc_expr *e) +{ + gfc_expr *result; + gfc_ref *ref; + int i; + + result = gfc_copy_expr (e); + + /* Change the last array reference from AR_ELEMENT to AR_FULL. */ + for (ref = result->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->next == NULL) + { + if (ref->u.ar.dimen == 0 + && ref->u.ar.as && ref->u.ar.as->corank) + return result; + + ref->u.ar.type = AR_FULL; + + for (i = 0; i < ref->u.ar.dimen; i++) + ref->u.ar.start[i] = ref->u.ar.end[i] = ref->u.ar.stride[i] = NULL; + + break; + } + + gfc_free_shape (&result->shape, result->rank); + + /* Recalculate rank, shape, etc. */ + gfc_resolve_expr (result); + return result; +} + + +/* If the last ref of an expression is an array ref, return a copy of the + expression with that one removed. Otherwise, a copy of the original + expression. This is used for allocate-expressions and pointer assignment + LHS, where there may be an array specification that needs to be stripped + off when using gfc_check_vardef_context. */ + +static gfc_expr* +remove_last_array_ref (gfc_expr* e) +{ + gfc_expr* e2; + gfc_ref** r; + + e2 = gfc_copy_expr (e); + for (r = &e2->ref; *r; r = &(*r)->next) + if ((*r)->type == REF_ARRAY && !(*r)->next) + { + gfc_free_ref_list (*r); + *r = NULL; + break; + } + + return e2; +} + + +/* Used in resolve_allocate_expr to check that a allocation-object and + a source-expr are conformable. This does not catch all possible + cases; in particular a runtime checking is needed. */ + +static bool +conformable_arrays (gfc_expr *e1, gfc_expr *e2) +{ + gfc_ref *tail; + for (tail = e2->ref; tail && tail->next; tail = tail->next); + + /* First compare rank. */ + if ((tail && (!tail->u.ar.as || e1->rank != tail->u.ar.as->rank)) + || (!tail && e1->rank != e2->rank)) + { + gfc_error ("Source-expr at %L must be scalar or have the " + "same rank as the allocate-object at %L", + &e1->where, &e2->where); + return false; + } + + if (e1->shape) + { + int i; + mpz_t s; + + mpz_init (s); + + for (i = 0; i < e1->rank; i++) + { + if (tail->u.ar.start[i] == NULL) + break; + + if (tail->u.ar.end[i]) + { + mpz_set (s, tail->u.ar.end[i]->value.integer); + mpz_sub (s, s, tail->u.ar.start[i]->value.integer); + mpz_add_ui (s, s, 1); + } + else + { + mpz_set (s, tail->u.ar.start[i]->value.integer); + } + + if (mpz_cmp (e1->shape[i], s) != 0) + { + gfc_error ("Source-expr at %L and allocate-object at %L must " + "have the same shape", &e1->where, &e2->where); + mpz_clear (s); + return false; + } + } + + mpz_clear (s); + } + + return true; +} + + +/* 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 bool +resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool *array_alloc_wo_spec) +{ + int i, pointer, allocatable, dimension, is_abstract; + int codimension; + bool coindexed; + bool unlimited; + symbol_attribute attr; + gfc_ref *ref, *ref2; + gfc_expr *e2; + gfc_array_ref *ar; + gfc_symbol *sym = NULL; + gfc_alloc *a; + gfc_component *c; + bool t; + + /* Mark the utmost array component as being in allocate to allow DIMEN_STAR + checking of coarrays. */ + for (ref = e->ref; ref; ref = ref->next) + if (ref->next == NULL) + break; + + if (ref && ref->type == REF_ARRAY) + ref->u.ar.in_allocate = true; + + if (!gfc_resolve_expr (e)) + goto 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->symtree) + sym = e->symtree->n.sym; + + /* Check whether ultimate component is abstract and CLASS. */ + is_abstract = 0; + + /* Is the allocate-object unlimited polymorphic? */ + unlimited = UNLIMITED_POLY(e); + + if (e->expr_type != EXPR_VARIABLE) + { + allocatable = 0; + attr = gfc_expr_attr (e); + pointer = attr.pointer; + dimension = attr.dimension; + codimension = attr.codimension; + } + else + { + if (sym->ts.type == BT_CLASS && CLASS_DATA (sym)) + { + allocatable = CLASS_DATA (sym)->attr.allocatable; + pointer = CLASS_DATA (sym)->attr.class_pointer; + dimension = CLASS_DATA (sym)->attr.dimension; + codimension = CLASS_DATA (sym)->attr.codimension; + is_abstract = CLASS_DATA (sym)->attr.abstract; + } + else + { + allocatable = sym->attr.allocatable; + pointer = sym->attr.pointer; + dimension = sym->attr.dimension; + codimension = sym->attr.codimension; + } + + coindexed = false; + + for (ref = e->ref; ref; ref2 = ref, ref = ref->next) + { + switch (ref->type) + { + case REF_ARRAY: + if (ref->u.ar.codimen > 0) + { + int n; + for (n = ref->u.ar.dimen; + n < ref->u.ar.dimen + ref->u.ar.codimen; n++) + if (ref->u.ar.dimen_type[n] != DIMEN_THIS_IMAGE) + { + coindexed = true; + break; + } + } + + if (ref->next != NULL) + pointer = 0; + break; + + case REF_COMPONENT: + /* F2008, C644. */ + if (coindexed) + { + gfc_error ("Coindexed allocatable object at %L", + &e->where); + goto failure; + } + + c = ref->u.c.component; + if (c->ts.type == BT_CLASS) + { + allocatable = CLASS_DATA (c)->attr.allocatable; + pointer = CLASS_DATA (c)->attr.class_pointer; + dimension = CLASS_DATA (c)->attr.dimension; + codimension = CLASS_DATA (c)->attr.codimension; + is_abstract = CLASS_DATA (c)->attr.abstract; + } + else + { + allocatable = c->attr.allocatable; + pointer = c->attr.pointer; + dimension = c->attr.dimension; + codimension = c->attr.codimension; + is_abstract = c->attr.abstract; + } + break; + + case REF_SUBSTRING: + case REF_INQUIRY: + allocatable = 0; + pointer = 0; + break; + } + } + } + + /* Check for F08:C628 (F2018:C932). Each allocate-object shall be a data + pointer or an allocatable variable. */ + if (allocatable == 0 && pointer == 0) + { + gfc_error ("Allocate-object at %L must be ALLOCATABLE or a POINTER", + &e->where); + goto failure; + } + + /* Some checks for the SOURCE tag. */ + if (code->expr3) + { + /* Check F03:C631. */ + if (!gfc_type_compatible (&e->ts, &code->expr3->ts)) + { + gfc_error ("Type of entity at %L is type incompatible with " + "source-expr at %L", &e->where, &code->expr3->where); + goto failure; + } + + /* Check F03:C632 and restriction following Note 6.18. */ + if (code->expr3->rank > 0 && !conformable_arrays (code->expr3, e)) + goto failure; + + /* Check F03:C633. */ + if (code->expr3->ts.kind != e->ts.kind && !unlimited) + { + gfc_error ("The allocate-object at %L and the source-expr at %L " + "shall have the same kind type parameter", + &e->where, &code->expr3->where); + goto failure; + } + + /* Check F2008, C642. */ + if (code->expr3->ts.type == BT_DERIVED + && ((codimension && gfc_expr_attr (code->expr3).lock_comp) + || (code->expr3->ts.u.derived->from_intmod + == INTMOD_ISO_FORTRAN_ENV + && code->expr3->ts.u.derived->intmod_sym_id + == ISOFORTRAN_LOCK_TYPE))) + { + gfc_error ("The source-expr at %L shall neither be of type " + "LOCK_TYPE nor have a LOCK_TYPE component if " + "allocate-object at %L is a coarray", + &code->expr3->where, &e->where); + goto failure; + } + + /* Check TS18508, C702/C703. */ + if (code->expr3->ts.type == BT_DERIVED + && ((codimension && gfc_expr_attr (code->expr3).event_comp) + || (code->expr3->ts.u.derived->from_intmod + == INTMOD_ISO_FORTRAN_ENV + && code->expr3->ts.u.derived->intmod_sym_id + == ISOFORTRAN_EVENT_TYPE))) + { + gfc_error ("The source-expr at %L shall neither be of type " + "EVENT_TYPE nor have a EVENT_TYPE component if " + "allocate-object at %L is a coarray", + &code->expr3->where, &e->where); + goto failure; + } + } + + /* Check F08:C629. */ + if (is_abstract && code->ext.alloc.ts.type == BT_UNKNOWN + && !code->expr3) + { + gcc_assert (e->ts.type == BT_CLASS); + gfc_error ("Allocating %s of ABSTRACT base type at %L requires a " + "type-spec or source-expr", sym->name, &e->where); + goto failure; + } + + /* Check F08:C632. */ + if (code->ext.alloc.ts.type == BT_CHARACTER && !e->ts.deferred + && !UNLIMITED_POLY (e)) + { + int cmp; + + if (!e->ts.u.cl->length) + goto failure; + + cmp = gfc_dep_compare_expr (e->ts.u.cl->length, + code->ext.alloc.ts.u.cl->length); + if (cmp == 1 || cmp == -1 || cmp == -3) + { + gfc_error ("Allocating %s at %L with type-spec requires the same " + "character-length parameter as in the declaration", + sym->name, &e->where); + goto failure; + } + } + + /* In the variable definition context checks, gfc_expr_attr is used + on the expression. This is fooled by the array specification + present in e, thus we have to eliminate that one temporarily. */ + e2 = remove_last_array_ref (e); + t = true; + if (t && pointer) + t = gfc_check_vardef_context (e2, true, true, false, + _("ALLOCATE object")); + if (t) + t = gfc_check_vardef_context (e2, false, true, false, + _("ALLOCATE object")); + gfc_free_expr (e2); + if (!t) + goto failure; + + if (e->ts.type == BT_CLASS && CLASS_DATA (e)->attr.dimension + && !code->expr3 && code->ext.alloc.ts.type == BT_DERIVED) + { + /* For class arrays, the initialization with SOURCE is done + using _copy and trans_call. It is convenient to exploit that + when the allocated type is different from the declared type but + no SOURCE exists by setting expr3. */ + code->expr3 = gfc_default_initializer (&code->ext.alloc.ts); + } + else if (flag_coarray != GFC_FCOARRAY_LIB && e->ts.type == BT_DERIVED + && e->ts.u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV + && e->ts.u.derived->intmod_sym_id == ISOFORTRAN_EVENT_TYPE) + { + /* We have to zero initialize the integer variable. */ + code->expr3 = gfc_get_int_expr (gfc_default_integer_kind, &e->where, 0); + } + + if (e->ts.type == BT_CLASS && !unlimited && !UNLIMITED_POLY (code->expr3)) + { + /* Make sure the vtab symbol is present when + the module variables are generated. */ + gfc_typespec ts = e->ts; + if (code->expr3) + ts = code->expr3->ts; + else if (code->ext.alloc.ts.type == BT_DERIVED) + ts = code->ext.alloc.ts; + + /* Finding the vtab also publishes the type's symbol. Therefore this + statement is necessary. */ + gfc_find_derived_vtab (ts.u.derived); + } + else if (unlimited && !UNLIMITED_POLY (code->expr3)) + { + /* Again, make sure the vtab symbol is present when + the module variables are generated. */ + gfc_typespec *ts = NULL; + if (code->expr3) + ts = &code->expr3->ts; + else + ts = &code->ext.alloc.ts; + + gcc_assert (ts); + + /* Finding the vtab also publishes the type's symbol. Therefore this + statement is necessary. */ + gfc_find_vtab (ts); + } + + if (dimension == 0 && codimension == 0) + goto success; + + /* Make sure the last reference node is an array specification. */ + + if (!ref2 || ref2->type != REF_ARRAY || ref2->u.ar.type == AR_FULL + || (dimension && ref2->u.ar.dimen == 0)) + { + /* F08:C633. */ + if (code->expr3) + { + if (!gfc_notify_std (GFC_STD_F2008, "Array specification required " + "in ALLOCATE statement at %L", &e->where)) + goto failure; + if (code->expr3->rank != 0) + *array_alloc_wo_spec = true; + else + { + gfc_error ("Array specification or array-valued SOURCE= " + "expression required in ALLOCATE statement at %L", + &e->where); + goto failure; + } + } + else + { + gfc_error ("Array specification required in ALLOCATE statement " + "at %L", &e->where); + goto failure; + } + } + + /* Make sure that the array section reference makes sense in the + context of an ALLOCATE specification. */ + + ar = &ref2->u.ar; + + if (codimension) + for (i = ar->dimen; i < ar->dimen + ar->codimen; i++) + { + switch (ar->dimen_type[i]) + { + case DIMEN_THIS_IMAGE: + gfc_error ("Coarray specification required in ALLOCATE statement " + "at %L", &e->where); + goto failure; + + case DIMEN_RANGE: + if (ar->start[i] == 0 || ar->end[i] == 0) + { + /* If ar->stride[i] is NULL, we issued a previous error. */ + if (ar->stride[i] == NULL) + gfc_error ("Bad array specification in ALLOCATE statement " + "at %L", &e->where); + goto failure; + } + else if (gfc_dep_compare_expr (ar->start[i], ar->end[i]) == 1) + { + gfc_error ("Upper cobound is less than lower cobound at %L", + &ar->start[i]->where); + goto failure; + } + break; + + case DIMEN_ELEMENT: + if (ar->start[i]->expr_type == EXPR_CONSTANT) + { + gcc_assert (ar->start[i]->ts.type == BT_INTEGER); + if (mpz_cmp_si (ar->start[i]->value.integer, 1) < 0) + { + gfc_error ("Upper cobound is less than lower cobound " + "of 1 at %L", &ar->start[i]->where); + goto failure; + } + } + break; + + case DIMEN_STAR: + break; + + default: + gfc_error ("Bad array specification in ALLOCATE statement at %L", + &e->where); + goto failure; + + } + } + for (i = 0; i < ar->dimen; i++) + { + if (ar->type == AR_ELEMENT || ar->type == AR_FULL) + goto check_symbols; + + 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: + case DIMEN_STAR: + case DIMEN_THIS_IMAGE: + gfc_error ("Bad array specification in ALLOCATE statement at %L", + &e->where); + goto failure; + } + +check_symbols: + for (a = code->ext.alloc.list; a; a = a->next) + { + sym = a->expr->symtree->n.sym; + + /* TODO - check derived type components. */ + if (gfc_bt_struct (sym->ts.type) || sym->ts.type == BT_CLASS) + continue; + + if ((ar->start[i] != NULL + && gfc_find_sym_in_expr (sym, ar->start[i])) + || (ar->end[i] != NULL + && gfc_find_sym_in_expr (sym, ar->end[i]))) + { + gfc_error ("%qs must not appear in the array specification at " + "%L in the same ALLOCATE statement where it is " + "itself allocated", sym->name, &ar->where); + goto failure; + } + } + } + + for (i = ar->dimen; i < ar->codimen + ar->dimen; i++) + { + if (ar->dimen_type[i] == DIMEN_ELEMENT + || ar->dimen_type[i] == DIMEN_RANGE) + { + if (i == (ar->dimen + ar->codimen - 1)) + { + gfc_error ("Expected '*' in coindex specification in ALLOCATE " + "statement at %L", &e->where); + goto failure; + } + continue; + } + + if (ar->dimen_type[i] == DIMEN_STAR && i == (ar->dimen + ar->codimen - 1) + && ar->stride[i] == NULL) + break; + + gfc_error ("Bad coarray specification in ALLOCATE statement at %L", + &e->where); + goto failure; + } + +success: + return true; + +failure: + return false; +} + + +static void +resolve_allocate_deallocate (gfc_code *code, const char *fcn) +{ + gfc_expr *stat, *errmsg, *pe, *qe; + gfc_alloc *a, *p, *q; + + stat = code->expr1; + errmsg = code->expr2; + + /* Check the stat variable. */ + if (stat) + { + if (!gfc_check_vardef_context (stat, false, false, false, + _("STAT variable"))) + goto done_stat; + + if (stat->ts.type != BT_INTEGER + || stat->rank > 0) + gfc_error ("Stat-variable at %L must be a scalar INTEGER " + "variable", &stat->where); + + if (stat->expr_type == EXPR_CONSTANT || stat->symtree == NULL) + goto done_stat; + + /* F2018:9.7.4: The stat-variable shall not be allocated or deallocated + * within the ALLOCATE or DEALLOCATE statement in which it appears ... + */ + for (p = code->ext.alloc.list; p; p = p->next) + if (p->expr->symtree->n.sym->name == stat->symtree->n.sym->name) + { + gfc_ref *ref1, *ref2; + bool found = true; + + for (ref1 = p->expr->ref, ref2 = stat->ref; ref1 && ref2; + ref1 = ref1->next, ref2 = ref2->next) + { + if (ref1->type != REF_COMPONENT || ref2->type != REF_COMPONENT) + continue; + if (ref1->u.c.component->name != ref2->u.c.component->name) + { + found = false; + break; + } + } + + if (found) + { + gfc_error ("Stat-variable at %L shall not be %sd within " + "the same %s statement", &stat->where, fcn, fcn); + break; + } + } + } + +done_stat: + + /* Check the errmsg variable. */ + if (errmsg) + { + if (!stat) + gfc_warning (0, "ERRMSG at %L is useless without a STAT tag", + &errmsg->where); + + if (!gfc_check_vardef_context (errmsg, false, false, false, + _("ERRMSG variable"))) + goto done_errmsg; + + /* F18:R928 alloc-opt is ERRMSG = errmsg-variable + F18:R930 errmsg-variable is scalar-default-char-variable + F18:R906 default-char-variable is variable + F18:C906 default-char-variable shall be default character. */ + if (errmsg->ts.type != BT_CHARACTER + || errmsg->rank > 0 + || errmsg->ts.kind != gfc_default_character_kind) + gfc_error ("ERRMSG variable at %L shall be a scalar default CHARACTER " + "variable", &errmsg->where); + + if (errmsg->expr_type == EXPR_CONSTANT || errmsg->symtree == NULL) + goto done_errmsg; + + /* F2018:9.7.5: The errmsg-variable shall not be allocated or deallocated + * within the ALLOCATE or DEALLOCATE statement in which it appears ... + */ + for (p = code->ext.alloc.list; p; p = p->next) + if (p->expr->symtree->n.sym->name == errmsg->symtree->n.sym->name) + { + gfc_ref *ref1, *ref2; + bool found = true; + + for (ref1 = p->expr->ref, ref2 = errmsg->ref; ref1 && ref2; + ref1 = ref1->next, ref2 = ref2->next) + { + if (ref1->type != REF_COMPONENT || ref2->type != REF_COMPONENT) + continue; + if (ref1->u.c.component->name != ref2->u.c.component->name) + { + found = false; + break; + } + } + + if (found) + { + gfc_error ("Errmsg-variable at %L shall not be %sd within " + "the same %s statement", &errmsg->where, fcn, fcn); + break; + } + } + } + +done_errmsg: + + /* Check that an allocate-object appears only once in the statement. */ + + for (p = code->ext.alloc.list; p; p = p->next) + { + pe = p->expr; + for (q = p->next; q; q = q->next) + { + qe = q->expr; + if (pe->symtree->n.sym->name == qe->symtree->n.sym->name) + { + /* This is a potential collision. */ + gfc_ref *pr = pe->ref; + gfc_ref *qr = qe->ref; + + /* Follow the references until + a) They start to differ, in which case there is no error; + you can deallocate a%b and a%c in a single statement + b) Both of them stop, which is an error + c) One of them stops, which is also an error. */ + while (1) + { + if (pr == NULL && qr == NULL) + { + gfc_error ("Allocate-object at %L also appears at %L", + &pe->where, &qe->where); + break; + } + else if (pr != NULL && qr == NULL) + { + gfc_error ("Allocate-object at %L is subobject of" + " object at %L", &pe->where, &qe->where); + break; + } + else if (pr == NULL && qr != NULL) + { + gfc_error ("Allocate-object at %L is subobject of" + " object at %L", &qe->where, &pe->where); + break; + } + /* Here, pr != NULL && qr != NULL */ + gcc_assert(pr->type == qr->type); + if (pr->type == REF_ARRAY) + { + /* Handle cases like allocate(v(3)%x(3), v(2)%x(3)), + which are legal. */ + gcc_assert (qr->type == REF_ARRAY); + + if (pr->next && qr->next) + { + int i; + gfc_array_ref *par = &(pr->u.ar); + gfc_array_ref *qar = &(qr->u.ar); + + for (i=0; i<par->dimen; i++) + { + if ((par->start[i] != NULL + || qar->start[i] != NULL) + && gfc_dep_compare_expr (par->start[i], + qar->start[i]) != 0) + goto break_label; + } + } + } + else + { + if (pr->u.c.component->name != qr->u.c.component->name) + break; + } + + pr = pr->next; + qr = qr->next; + } + break_label: + ; + } + } + } + + if (strcmp (fcn, "ALLOCATE") == 0) + { + bool arr_alloc_wo_spec = false; + + /* Resolving the expr3 in the loop over all objects to allocate would + execute loop invariant code for each loop item. Therefore do it just + once here. */ + if (code->expr3 && code->expr3->mold + && code->expr3->ts.type == BT_DERIVED) + { + /* Default initialization via MOLD (non-polymorphic). */ + gfc_expr *rhs = gfc_default_initializer (&code->expr3->ts); + if (rhs != NULL) + { + gfc_resolve_expr (rhs); + gfc_free_expr (code->expr3); + code->expr3 = rhs; + } + } + for (a = code->ext.alloc.list; a; a = a->next) + resolve_allocate_expr (a->expr, code, &arr_alloc_wo_spec); + + if (arr_alloc_wo_spec && code->expr3) + { + /* Mark the allocate to have to take the array specification + from the expr3. */ + code->ext.alloc.arr_spec_from_expr3 = 1; + } + } + else + { + for (a = code->ext.alloc.list; a; a = a->next) + resolve_deallocate_expr (a->expr); + } +} + + +/************ 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. + We have op1 = (:L), (K:L) or (K:) and op2 = (:N), (M:N) or (M:). + There are nine situations to check. */ + +static int +compare_cases (const gfc_case *op1, const gfc_case *op2) +{ + int retval; + + if (op1->low == NULL) /* op1 = (:L) */ + { + /* op2 = (:N), so overlap. */ + retval = 0; + /* op2 = (M:) or (M:N), L < M */ + if (op2->low != NULL + && gfc_compare_expr (op1->high, op2->low, INTRINSIC_LT) < 0) + retval = -1; + } + else if (op1->high == NULL) /* op1 = (K:) */ + { + /* op2 = (M:), so overlap. */ + retval = 0; + /* op2 = (:N) or (M:N), K > N */ + if (op2->high != NULL + && gfc_compare_expr (op1->low, op2->high, INTRINSIC_GT) > 0) + retval = 1; + } + else /* op1 = (K:L) */ + { + if (op2->low == NULL) /* op2 = (:N), K > N */ + retval = (gfc_compare_expr (op1->low, op2->high, INTRINSIC_GT) > 0) + ? 1 : 0; + else if (op2->high == NULL) /* op2 = (M:), L < M */ + retval = (gfc_compare_expr (op1->high, op2->low, INTRINSIC_LT) < 0) + ? -1 : 0; + else /* op2 = (M:N) */ + { + retval = 0; + /* L < M */ + if (gfc_compare_expr (op1->high, op2->low, INTRINSIC_LT) < 0) + retval = -1; + /* K > N */ + else if (gfc_compare_expr (op1->low, op2->high, INTRINSIC_GT) > 0) + retval = 1; + } + } + + return retval; +} + + +/* 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 stepping 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. Return false if anything is wrong. */ + +static bool +validate_case_label_expr (gfc_expr *e, gfc_expr *case_expr) +{ + if (e == NULL) return true; + + if (e->ts.type != case_expr->ts.type) + { + gfc_error ("Expression in CASE statement at %L must be of type %s", + &e->where, gfc_basic_typename (case_expr->ts.type)); + return false; + } + + /* C805 (R808) For a given case-construct, each case-value shall be of + the same type as case-expr. For character type, length differences + are allowed, but the kind type parameters shall be the same. */ + + if (case_expr->ts.type == BT_CHARACTER && e->ts.kind != case_expr->ts.kind) + { + gfc_error ("Expression in CASE statement at %L must be of kind %d", + &e->where, case_expr->ts.kind); + return false; + } + + /* Convert the case value kind to that of case expression kind, + if needed */ + + if (e->ts.kind != case_expr->ts.kind) + gfc_convert_type_warn (e, &case_expr->ts, 2, 0); + + if (e->rank != 0) + { + gfc_error ("Expression in CASE statement at %L must be scalar", + &e->where); + return false; + } + + return true; +} + + +/* 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. Fortunately 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, bool select_type) +{ + gfc_code *body; + gfc_expr *case_expr; + gfc_case *cp, *default_case, *tail, *head; + int seen_unreachable; + int seen_logical; + int ncases; + bt type; + bool t; + + if (code->expr1 == 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->expr1 = code->expr2; + code->expr2 = NULL; + return; + } + + case_expr = code->expr1; + type = case_expr->ts.type; + + /* F08:C830. */ + 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)); + + /* Punt. Going on here just produce more garbage error messages. */ + return; + } + + /* F08:R842. */ + if (!select_type && case_expr->rank != 0) + { + gfc_error ("Argument of SELECT statement at %L must be a scalar " + "expression", &case_expr->where); + + /* Punt. */ + return; + } + + /* Raise a warning if an INTEGER case value exceeds the range of + the case-expr. Later, all expressions will be promoted to the + largest kind of all case-labels. */ + + if (type == BT_INTEGER) + for (body = code->block; body; body = body->block) + for (cp = body->ext.block.case_list; cp; cp = cp->next) + { + if (cp->low + && gfc_check_integer_range (cp->low->value.integer, + case_expr->ts.kind) != ARITH_OK) + gfc_warning (0, "Expression in CASE statement at %L is " + "not in the range of %s", &cp->low->where, + gfc_typename (case_expr)); + + if (cp->high + && cp->low != cp->high + && gfc_check_integer_range (cp->high->value.integer, + case_expr->ts.kind) != ARITH_OK) + gfc_warning (0, "Expression in CASE statement at %L is " + "not in the range of %s", &cp->high->where, + gfc_typename (case_expr)); + } + + /* PR 19168 has a long discussion concerning a mismatch of the kinds + of the SELECT CASE expression and its CASE values. Walk the lists + of case values, and if we find a mismatch, promote case_expr to + the appropriate kind. */ + + if (type == BT_LOGICAL || type == BT_INTEGER) + { + for (body = code->block; body; body = body->block) + { + /* Walk the case label list. */ + for (cp = body->ext.block.case_list; cp; cp = cp->next) + { + /* Intercept the DEFAULT case. It does not have a kind. */ + if (cp->low == NULL && cp->high == NULL) + continue; + + /* Unreachable case ranges are discarded, so ignore. */ + if (cp->low != NULL && cp->high != NULL + && cp->low != cp->high + && gfc_compare_expr (cp->low, cp->high, INTRINSIC_GT) > 0) + continue; + + if (cp->low != NULL + && case_expr->ts.kind != gfc_kind_max(case_expr, cp->low)) + gfc_convert_type_warn (case_expr, &cp->low->ts, 1, 0); + + if (cp->high != NULL + && case_expr->ts.kind != gfc_kind_max(case_expr, cp->high)) + gfc_convert_type_warn (case_expr, &cp->high->ts, 1, 0); + } + } + } + + /* Assume there is no DEFAULT case. */ + default_case = NULL; + head = tail = NULL; + ncases = 0; + seen_logical = 0; + + for (body = code->block; body; body = body->block) + { + /* Assume the CASE list is OK, and all CASE labels can be matched. */ + t = true; + seen_unreachable = 0; + + /* Walk the case label list, making sure that all case labels + are legal. */ + for (cp = body->ext.block.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 = false; + 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) + || !validate_case_label_expr (cp->high, case_expr)) + { + t = false; + 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 ? &cp->low->where : &cp->high->where); + t = false; + break; + } + + if (type == BT_LOGICAL && cp->low->expr_type == EXPR_CONSTANT) + { + int value; + value = cp->low->value.logical == 0 ? 2 : 1; + if (value & seen_logical) + { + gfc_error ("Constant logical value in CASE statement " + "is repeated at %L", + &cp->low->where); + t = false; + break; + } + seen_logical |= value; + } + + if (cp->low != NULL && cp->high != NULL + && cp->low != cp->high + && gfc_compare_expr (cp->low, cp->high, INTRINSIC_GT) > 0) + { + if (warn_surprising) + gfc_warning (OPT_Wsurprising, + "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) + 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.block.case_list != NULL + && body->ext.block.case_list->unreachable) + { + gfc_case *n = body->ext.block.case_list; + body->ext.block.case_list = body->ext.block.case_list->next; + n->next = NULL; + gfc_free_case_list (n); + } + + /* Strip all other unreachable cases. */ + if (body->ext.block.case_list) + { + for (cp = body->ext.block.case_list; cp && 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.block.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 (warn_surprising && type == BT_LOGICAL && ncases > 2) + gfc_warning (OPT_Wsurprising, + "Logical SELECT CASE block at %L has more that two cases", + &code->loc); +} + + +/* Check if a derived type is extensible. */ + +bool +gfc_type_is_extensible (gfc_symbol *sym) +{ + return !(sym->attr.is_bind_c || sym->attr.sequence + || (sym->attr.is_class + && sym->components->ts.u.derived->attr.unlimited_polymorphic)); +} + + +static void +resolve_types (gfc_namespace *ns); + +/* Resolve an associate-name: Resolve target and ensure the type-spec is + correct as well as possibly the array-spec. */ + +static void +resolve_assoc_var (gfc_symbol* sym, bool resolve_target) +{ + gfc_expr* target; + + gcc_assert (sym->assoc); + gcc_assert (sym->attr.flavor == FL_VARIABLE); + + /* If this is for SELECT TYPE, the target may not yet be set. In that + case, return. Resolution will be called later manually again when + this is done. */ + target = sym->assoc->target; + if (!target) + return; + gcc_assert (!sym->assoc->dangling); + + if (resolve_target && !gfc_resolve_expr (target)) + return; + + /* For variable targets, we get some attributes from the target. */ + if (target->expr_type == EXPR_VARIABLE) + { + gfc_symbol *tsym, *dsym; + + gcc_assert (target->symtree); + tsym = target->symtree->n.sym; + + if (gfc_expr_attr (target).proc_pointer) + { + gfc_error ("Associating entity %qs at %L is a procedure pointer", + tsym->name, &target->where); + return; + } + + if (tsym->attr.flavor == FL_PROCEDURE && tsym->generic + && (dsym = gfc_find_dt_in_generic (tsym)) != NULL + && dsym->attr.flavor == FL_DERIVED) + { + gfc_error ("Derived type %qs cannot be used as a variable at %L", + tsym->name, &target->where); + return; + } + + if (tsym->attr.flavor == FL_PROCEDURE) + { + bool is_error = true; + if (tsym->attr.function && tsym->result == tsym) + for (gfc_namespace *ns = sym->ns; ns; ns = ns->parent) + if (tsym == ns->proc_name) + { + is_error = false; + break; + } + if (is_error) + { + gfc_error ("Associating entity %qs at %L is a procedure name", + tsym->name, &target->where); + return; + } + } + + sym->attr.asynchronous = tsym->attr.asynchronous; + sym->attr.volatile_ = tsym->attr.volatile_; + + sym->attr.target = tsym->attr.target + || gfc_expr_attr (target).pointer; + if (is_subref_array (target)) + sym->attr.subref_array_pointer = 1; + } + else if (target->ts.type == BT_PROCEDURE) + { + gfc_error ("Associating selector-expression at %L yields a procedure", + &target->where); + return; + } + + if (target->expr_type == EXPR_NULL) + { + gfc_error ("Selector at %L cannot be NULL()", &target->where); + return; + } + else if (target->ts.type == BT_UNKNOWN) + { + gfc_error ("Selector at %L has no type", &target->where); + return; + } + + /* Get type if this was not already set. Note that it can be + some other type than the target in case this is a SELECT TYPE + selector! So we must not update when the type is already there. */ + if (sym->ts.type == BT_UNKNOWN) + sym->ts = target->ts; + + gcc_assert (sym->ts.type != BT_UNKNOWN); + + /* See if this is a valid association-to-variable. */ + sym->assoc->variable = (target->expr_type == EXPR_VARIABLE + && !gfc_has_vector_subscript (target)); + + /* Finally resolve if this is an array or not. */ + if (sym->attr.dimension && target->rank == 0) + { + /* primary.c makes the assumption that a reference to an associate + name followed by a left parenthesis is an array reference. */ + if (sym->ts.type != BT_CHARACTER) + gfc_error ("Associate-name %qs at %L is used as array", + sym->name, &sym->declared_at); + sym->attr.dimension = 0; + return; + } + + + /* We cannot deal with class selectors that need temporaries. */ + if (target->ts.type == BT_CLASS + && gfc_ref_needs_temporary_p (target->ref)) + { + gfc_error ("CLASS selector at %L needs a temporary which is not " + "yet implemented", &target->where); + return; + } + + if (target->ts.type == BT_CLASS) + gfc_fix_class_refs (target); + + if (target->rank != 0 && !sym->attr.select_rank_temporary) + { + gfc_array_spec *as; + /* The rank may be incorrectly guessed at parsing, therefore make sure + it is corrected now. */ + if (sym->ts.type != BT_CLASS && (!sym->as || sym->assoc->rankguessed)) + { + if (!sym->as) + sym->as = gfc_get_array_spec (); + as = sym->as; + as->rank = target->rank; + as->type = AS_DEFERRED; + as->corank = gfc_get_corank (target); + sym->attr.dimension = 1; + if (as->corank != 0) + sym->attr.codimension = 1; + } + else if (sym->ts.type == BT_CLASS + && CLASS_DATA (sym) + && (!CLASS_DATA (sym)->as || sym->assoc->rankguessed)) + { + if (!CLASS_DATA (sym)->as) + CLASS_DATA (sym)->as = gfc_get_array_spec (); + as = CLASS_DATA (sym)->as; + as->rank = target->rank; + as->type = AS_DEFERRED; + as->corank = gfc_get_corank (target); + CLASS_DATA (sym)->attr.dimension = 1; + if (as->corank != 0) + CLASS_DATA (sym)->attr.codimension = 1; + } + } + else if (!sym->attr.select_rank_temporary) + { + /* target's rank is 0, but the type of the sym is still array valued, + which has to be corrected. */ + if (sym->ts.type == BT_CLASS && sym->ts.u.derived + && CLASS_DATA (sym) && CLASS_DATA (sym)->as) + { + gfc_array_spec *as; + symbol_attribute attr; + /* The associated variable's type is still the array type + correct this now. */ + gfc_typespec *ts = &target->ts; + gfc_ref *ref; + gfc_component *c; + for (ref = target->ref; ref != NULL; ref = ref->next) + { + switch (ref->type) + { + case REF_COMPONENT: + ts = &ref->u.c.component->ts; + break; + case REF_ARRAY: + if (ts->type == BT_CLASS) + ts = &ts->u.derived->components->ts; + break; + default: + break; + } + } + /* Create a scalar instance of the current class type. Because the + rank of a class array goes into its name, the type has to be + rebuild. The alternative of (re-)setting just the attributes + and as in the current type, destroys the type also in other + places. */ + as = NULL; + sym->ts = *ts; + sym->ts.type = BT_CLASS; + attr = CLASS_DATA (sym) ? CLASS_DATA (sym)->attr : sym->attr; + attr.class_ok = 0; + attr.associate_var = 1; + attr.dimension = attr.codimension = 0; + attr.class_pointer = 1; + if (!gfc_build_class_symbol (&sym->ts, &attr, &as)) + gcc_unreachable (); + /* Make sure the _vptr is set. */ + c = gfc_find_component (sym->ts.u.derived, "_vptr", true, true, NULL); + if (c->ts.u.derived == NULL) + c->ts.u.derived = gfc_find_derived_vtab (sym->ts.u.derived); + CLASS_DATA (sym)->attr.pointer = 1; + CLASS_DATA (sym)->attr.class_pointer = 1; + gfc_set_sym_referenced (sym->ts.u.derived); + gfc_commit_symbol (sym->ts.u.derived); + /* _vptr now has the _vtab in it, change it to the _vtype. */ + if (c->ts.u.derived->attr.vtab) + c->ts.u.derived = c->ts.u.derived->ts.u.derived; + c->ts.u.derived->ns->types_resolved = 0; + resolve_types (c->ts.u.derived->ns); + } + } + + /* Mark this as an associate variable. */ + sym->attr.associate_var = 1; + + /* Fix up the type-spec for CHARACTER types. */ + if (sym->ts.type == BT_CHARACTER && !sym->attr.select_type_temporary) + { + if (!sym->ts.u.cl) + sym->ts.u.cl = target->ts.u.cl; + + if (sym->ts.deferred && target->expr_type == EXPR_VARIABLE + && target->symtree->n.sym->attr.dummy + && sym->ts.u.cl == target->ts.u.cl) + { + sym->ts.u.cl = gfc_new_charlen (sym->ns, NULL); + sym->ts.deferred = 1; + } + + if (!sym->ts.u.cl->length + && !sym->ts.deferred + && target->expr_type == EXPR_CONSTANT) + { + sym->ts.u.cl->length = + gfc_get_int_expr (gfc_charlen_int_kind, NULL, + target->value.character.length); + } + else if ((!sym->ts.u.cl->length + || sym->ts.u.cl->length->expr_type != EXPR_CONSTANT) + && target->expr_type != EXPR_VARIABLE) + { + sym->ts.u.cl = gfc_new_charlen (sym->ns, NULL); + sym->ts.deferred = 1; + + /* This is reset in trans-stmt.c after the assignment + of the target expression to the associate name. */ + sym->attr.allocatable = 1; + } + } + + /* If the target is a good class object, so is the associate variable. */ + if (sym->ts.type == BT_CLASS && gfc_expr_attr (target).class_ok) + sym->attr.class_ok = 1; +} + + +/* Ensure that SELECT TYPE expressions have the correct rank and a full + array reference, where necessary. The symbols are artificial and so + the dimension attribute and arrayspec can also be set. In addition, + sometimes the expr1 arrives as BT_DERIVED, when the symbol is BT_CLASS. + This is corrected here as well.*/ + +static void +fixup_array_ref (gfc_expr **expr1, gfc_expr *expr2, + int rank, gfc_ref *ref) +{ + gfc_ref *nref = (*expr1)->ref; + gfc_symbol *sym1 = (*expr1)->symtree->n.sym; + gfc_symbol *sym2 = expr2 ? expr2->symtree->n.sym : NULL; + (*expr1)->rank = rank; + if (sym1->ts.type == BT_CLASS) + { + if ((*expr1)->ts.type != BT_CLASS) + (*expr1)->ts = sym1->ts; + + CLASS_DATA (sym1)->attr.dimension = 1; + if (CLASS_DATA (sym1)->as == NULL && sym2) + CLASS_DATA (sym1)->as + = gfc_copy_array_spec (CLASS_DATA (sym2)->as); + } + else + { + sym1->attr.dimension = 1; + if (sym1->as == NULL && sym2) + sym1->as = gfc_copy_array_spec (sym2->as); + } + + for (; nref; nref = nref->next) + if (nref->next == NULL) + break; + + if (ref && nref && nref->type != REF_ARRAY) + nref->next = gfc_copy_ref (ref); + else if (ref && !nref) + (*expr1)->ref = gfc_copy_ref (ref); +} + + +static gfc_expr * +build_loc_call (gfc_expr *sym_expr) +{ + gfc_expr *loc_call; + loc_call = gfc_get_expr (); + loc_call->expr_type = EXPR_FUNCTION; + gfc_get_sym_tree ("_loc", gfc_current_ns, &loc_call->symtree, false); + loc_call->symtree->n.sym->attr.flavor = FL_PROCEDURE; + loc_call->symtree->n.sym->attr.intrinsic = 1; + loc_call->symtree->n.sym->result = loc_call->symtree->n.sym; + gfc_commit_symbol (loc_call->symtree->n.sym); + loc_call->ts.type = BT_INTEGER; + loc_call->ts.kind = gfc_index_integer_kind; + loc_call->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_LOC); + loc_call->value.function.actual = gfc_get_actual_arglist (); + loc_call->value.function.actual->expr = sym_expr; + loc_call->where = sym_expr->where; + return loc_call; +} + +/* Resolve a SELECT TYPE statement. */ + +static void +resolve_select_type (gfc_code *code, gfc_namespace *old_ns) +{ + gfc_symbol *selector_type; + gfc_code *body, *new_st, *if_st, *tail; + gfc_code *class_is = NULL, *default_case = NULL; + gfc_case *c; + gfc_symtree *st; + char name[GFC_MAX_SYMBOL_LEN + 12 + 1]; + gfc_namespace *ns; + int error = 0; + int rank = 0; + gfc_ref* ref = NULL; + gfc_expr *selector_expr = NULL; + + ns = code->ext.block.ns; + gfc_resolve (ns); + + /* Check for F03:C813. */ + if (code->expr1->ts.type != BT_CLASS + && !(code->expr2 && code->expr2->ts.type == BT_CLASS)) + { + gfc_error ("Selector shall be polymorphic in SELECT TYPE statement " + "at %L", &code->loc); + return; + } + + if (!code->expr1->symtree->n.sym->attr.class_ok) + return; + + if (code->expr2) + { + gfc_ref *ref2 = NULL; + for (ref = code->expr2->ref; ref != NULL; ref = ref->next) + if (ref->type == REF_COMPONENT + && ref->u.c.component->ts.type == BT_CLASS) + ref2 = ref; + + if (ref2) + { + if (code->expr1->symtree->n.sym->attr.untyped) + code->expr1->symtree->n.sym->ts = ref2->u.c.component->ts; + selector_type = CLASS_DATA (ref2->u.c.component)->ts.u.derived; + } + else + { + if (code->expr1->symtree->n.sym->attr.untyped) + code->expr1->symtree->n.sym->ts = code->expr2->ts; + selector_type = CLASS_DATA (code->expr2) + ? CLASS_DATA (code->expr2)->ts.u.derived : code->expr2->ts.u.derived; + } + + if (code->expr2->rank + && code->expr1->ts.type == BT_CLASS + && CLASS_DATA (code->expr1)->as) + CLASS_DATA (code->expr1)->as->rank = code->expr2->rank; + + /* F2008: C803 The selector expression must not be coindexed. */ + if (gfc_is_coindexed (code->expr2)) + { + gfc_error ("Selector at %L must not be coindexed", + &code->expr2->where); + return; + } + + } + else + { + selector_type = CLASS_DATA (code->expr1)->ts.u.derived; + + if (gfc_is_coindexed (code->expr1)) + { + gfc_error ("Selector at %L must not be coindexed", + &code->expr1->where); + return; + } + } + + /* Loop over TYPE IS / CLASS IS cases. */ + for (body = code->block; body; body = body->block) + { + c = body->ext.block.case_list; + + if (!error) + { + /* Check for repeated cases. */ + for (tail = code->block; tail; tail = tail->block) + { + gfc_case *d = tail->ext.block.case_list; + if (tail == body) + break; + + if (c->ts.type == d->ts.type + && ((c->ts.type == BT_DERIVED + && c->ts.u.derived && d->ts.u.derived + && !strcmp (c->ts.u.derived->name, + d->ts.u.derived->name)) + || c->ts.type == BT_UNKNOWN + || (!(c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) + && c->ts.kind == d->ts.kind))) + { + gfc_error ("TYPE IS at %L overlaps with TYPE IS at %L", + &c->where, &d->where); + return; + } + } + } + + /* Check F03:C815. */ + if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) + && selector_type + && !selector_type->attr.unlimited_polymorphic + && !gfc_type_is_extensible (c->ts.u.derived)) + { + gfc_error ("Derived type %qs at %L must be extensible", + c->ts.u.derived->name, &c->where); + error++; + continue; + } + + /* Check F03:C816. */ + if (c->ts.type != BT_UNKNOWN + && selector_type && !selector_type->attr.unlimited_polymorphic + && ((c->ts.type != BT_DERIVED && c->ts.type != BT_CLASS) + || !gfc_type_is_extension_of (selector_type, c->ts.u.derived))) + { + if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) + gfc_error ("Derived type %qs at %L must be an extension of %qs", + c->ts.u.derived->name, &c->where, selector_type->name); + else + gfc_error ("Unexpected intrinsic type %qs at %L", + gfc_basic_typename (c->ts.type), &c->where); + error++; + continue; + } + + /* Check F03:C814. */ + if (c->ts.type == BT_CHARACTER + && (c->ts.u.cl->length != NULL || c->ts.deferred)) + { + gfc_error ("The type-spec at %L shall specify that each length " + "type parameter is assumed", &c->where); + error++; + continue; + } + + /* Intercept the DEFAULT case. */ + if (c->ts.type == BT_UNKNOWN) + { + /* Check F03:C818. */ + if (default_case) + { + gfc_error ("The DEFAULT CASE at %L cannot be followed " + "by a second DEFAULT CASE at %L", + &default_case->ext.block.case_list->where, &c->where); + error++; + continue; + } + + default_case = body; + } + } + + if (error > 0) + return; + + /* Transform SELECT TYPE statement to BLOCK and associate selector to + target if present. If there are any EXIT statements referring to the + SELECT TYPE construct, this is no problem because the gfc_code + reference stays the same and EXIT is equally possible from the BLOCK + it is changed to. */ + code->op = EXEC_BLOCK; + if (code->expr2) + { + gfc_association_list* assoc; + + assoc = gfc_get_association_list (); + assoc->st = code->expr1->symtree; + assoc->target = gfc_copy_expr (code->expr2); + assoc->target->where = code->expr2->where; + /* assoc->variable will be set by resolve_assoc_var. */ + + code->ext.block.assoc = assoc; + code->expr1->symtree->n.sym->assoc = assoc; + + resolve_assoc_var (code->expr1->symtree->n.sym, false); + } + else + code->ext.block.assoc = NULL; + + /* Ensure that the selector rank and arrayspec are available to + correct expressions in which they might be missing. */ + if (code->expr2 && code->expr2->rank) + { + rank = code->expr2->rank; + for (ref = code->expr2->ref; ref; ref = ref->next) + if (ref->next == NULL) + break; + if (ref && ref->type == REF_ARRAY) + ref = gfc_copy_ref (ref); + + /* Fixup expr1 if necessary. */ + if (rank) + fixup_array_ref (&code->expr1, code->expr2, rank, ref); + } + else if (code->expr1->rank) + { + rank = code->expr1->rank; + for (ref = code->expr1->ref; ref; ref = ref->next) + if (ref->next == NULL) + break; + if (ref && ref->type == REF_ARRAY) + ref = gfc_copy_ref (ref); + } + + /* Add EXEC_SELECT to switch on type. */ + new_st = gfc_get_code (code->op); + new_st->expr1 = code->expr1; + new_st->expr2 = code->expr2; + new_st->block = code->block; + code->expr1 = code->expr2 = NULL; + code->block = NULL; + if (!ns->code) + ns->code = new_st; + else + ns->code->next = new_st; + code = new_st; + code->op = EXEC_SELECT_TYPE; + + /* Use the intrinsic LOC function to generate an integer expression + for the vtable of the selector. Note that the rank of the selector + expression has to be set to zero. */ + gfc_add_vptr_component (code->expr1); + code->expr1->rank = 0; + code->expr1 = build_loc_call (code->expr1); + selector_expr = code->expr1->value.function.actual->expr; + + /* Loop over TYPE IS / CLASS IS cases. */ + for (body = code->block; body; body = body->block) + { + gfc_symbol *vtab; + gfc_expr *e; + c = body->ext.block.case_list; + + /* Generate an index integer expression for address of the + TYPE/CLASS vtable and store it in c->low. The hash expression + is stored in c->high and is used to resolve intrinsic cases. */ + if (c->ts.type != BT_UNKNOWN) + { + if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) + { + vtab = gfc_find_derived_vtab (c->ts.u.derived); + gcc_assert (vtab); + c->high = gfc_get_int_expr (gfc_integer_4_kind, NULL, + c->ts.u.derived->hash_value); + } + else + { + vtab = gfc_find_vtab (&c->ts); + gcc_assert (vtab && CLASS_DATA (vtab)->initializer); + e = CLASS_DATA (vtab)->initializer; + c->high = gfc_copy_expr (e); + if (c->high->ts.kind != gfc_integer_4_kind) + { + gfc_typespec ts; + ts.kind = gfc_integer_4_kind; + ts.type = BT_INTEGER; + gfc_convert_type_warn (c->high, &ts, 2, 0); + } + } + + e = gfc_lval_expr_from_sym (vtab); + c->low = build_loc_call (e); + } + else + continue; + + /* Associate temporary to selector. This should only be done + when this case is actually true, so build a new ASSOCIATE + that does precisely this here (instead of using the + 'global' one). */ + + if (c->ts.type == BT_CLASS) + sprintf (name, "__tmp_class_%s", c->ts.u.derived->name); + else if (c->ts.type == BT_DERIVED) + sprintf (name, "__tmp_type_%s", c->ts.u.derived->name); + else if (c->ts.type == BT_CHARACTER) + { + HOST_WIDE_INT charlen = 0; + if (c->ts.u.cl && c->ts.u.cl->length + && c->ts.u.cl->length->expr_type == EXPR_CONSTANT) + charlen = gfc_mpz_get_hwi (c->ts.u.cl->length->value.integer); + snprintf (name, sizeof (name), + "__tmp_%s_" HOST_WIDE_INT_PRINT_DEC "_%d", + gfc_basic_typename (c->ts.type), charlen, c->ts.kind); + } + else + sprintf (name, "__tmp_%s_%d", gfc_basic_typename (c->ts.type), + c->ts.kind); + + st = gfc_find_symtree (ns->sym_root, name); + gcc_assert (st->n.sym->assoc); + st->n.sym->assoc->target = gfc_get_variable_expr (selector_expr->symtree); + st->n.sym->assoc->target->where = selector_expr->where; + if (c->ts.type != BT_CLASS && c->ts.type != BT_UNKNOWN) + { + gfc_add_data_component (st->n.sym->assoc->target); + /* Fixup the target expression if necessary. */ + if (rank) + fixup_array_ref (&st->n.sym->assoc->target, NULL, rank, ref); + } + + new_st = gfc_get_code (EXEC_BLOCK); + new_st->ext.block.ns = gfc_build_block_ns (ns); + new_st->ext.block.ns->code = body->next; + body->next = new_st; + + /* Chain in the new list only if it is marked as dangling. Otherwise + there is a CASE label overlap and this is already used. Just ignore, + the error is diagnosed elsewhere. */ + if (st->n.sym->assoc->dangling) + { + new_st->ext.block.assoc = st->n.sym->assoc; + st->n.sym->assoc->dangling = 0; + } + + resolve_assoc_var (st->n.sym, false); + } + + /* Take out CLASS IS cases for separate treatment. */ + body = code; + while (body && body->block) + { + if (body->block->ext.block.case_list->ts.type == BT_CLASS) + { + /* Add to class_is list. */ + if (class_is == NULL) + { + class_is = body->block; + tail = class_is; + } + else + { + for (tail = class_is; tail->block; tail = tail->block) ; + tail->block = body->block; + tail = tail->block; + } + /* Remove from EXEC_SELECT list. */ + body->block = body->block->block; + tail->block = NULL; + } + else + body = body->block; + } + + if (class_is) + { + gfc_symbol *vtab; + + if (!default_case) + { + /* Add a default case to hold the CLASS IS cases. */ + for (tail = code; tail->block; tail = tail->block) ; + tail->block = gfc_get_code (EXEC_SELECT_TYPE); + tail = tail->block; + tail->ext.block.case_list = gfc_get_case (); + tail->ext.block.case_list->ts.type = BT_UNKNOWN; + tail->next = NULL; + default_case = tail; + } + + /* More than one CLASS IS block? */ + if (class_is->block) + { + gfc_code **c1,*c2; + bool swapped; + /* Sort CLASS IS blocks by extension level. */ + do + { + swapped = false; + for (c1 = &class_is; (*c1) && (*c1)->block; c1 = &((*c1)->block)) + { + c2 = (*c1)->block; + /* F03:C817 (check for doubles). */ + if ((*c1)->ext.block.case_list->ts.u.derived->hash_value + == c2->ext.block.case_list->ts.u.derived->hash_value) + { + gfc_error ("Double CLASS IS block in SELECT TYPE " + "statement at %L", + &c2->ext.block.case_list->where); + return; + } + if ((*c1)->ext.block.case_list->ts.u.derived->attr.extension + < c2->ext.block.case_list->ts.u.derived->attr.extension) + { + /* Swap. */ + (*c1)->block = c2->block; + c2->block = *c1; + *c1 = c2; + swapped = true; + } + } + } + while (swapped); + } + + /* Generate IF chain. */ + if_st = gfc_get_code (EXEC_IF); + new_st = if_st; + for (body = class_is; body; body = body->block) + { + new_st->block = gfc_get_code (EXEC_IF); + new_st = new_st->block; + /* Set up IF condition: Call _gfortran_is_extension_of. */ + new_st->expr1 = gfc_get_expr (); + new_st->expr1->expr_type = EXPR_FUNCTION; + new_st->expr1->ts.type = BT_LOGICAL; + new_st->expr1->ts.kind = 4; + new_st->expr1->value.function.name = gfc_get_string (PREFIX ("is_extension_of")); + new_st->expr1->value.function.isym = XCNEW (gfc_intrinsic_sym); + new_st->expr1->value.function.isym->id = GFC_ISYM_EXTENDS_TYPE_OF; + /* Set up arguments. */ + new_st->expr1->value.function.actual = gfc_get_actual_arglist (); + new_st->expr1->value.function.actual->expr = gfc_get_variable_expr (selector_expr->symtree); + new_st->expr1->value.function.actual->expr->where = code->loc; + new_st->expr1->where = code->loc; + gfc_add_vptr_component (new_st->expr1->value.function.actual->expr); + vtab = gfc_find_derived_vtab (body->ext.block.case_list->ts.u.derived); + st = gfc_find_symtree (vtab->ns->sym_root, vtab->name); + new_st->expr1->value.function.actual->next = gfc_get_actual_arglist (); + new_st->expr1->value.function.actual->next->expr = gfc_get_variable_expr (st); + new_st->expr1->value.function.actual->next->expr->where = code->loc; + /* Set up types in formal arg list. */ + new_st->expr1->value.function.isym->formal = XCNEW (gfc_intrinsic_arg); + new_st->expr1->value.function.isym->formal->ts = new_st->expr1->value.function.actual->expr->ts; + new_st->expr1->value.function.isym->formal->next = XCNEW (gfc_intrinsic_arg); + new_st->expr1->value.function.isym->formal->next->ts = new_st->expr1->value.function.actual->next->expr->ts; + + new_st->next = body->next; + } + if (default_case->next) + { + new_st->block = gfc_get_code (EXEC_IF); + new_st = new_st->block; + new_st->next = default_case->next; + } + + /* Replace CLASS DEFAULT code by the IF chain. */ + default_case->next = if_st; + } + + /* Resolve the internal code. This cannot be done earlier because + it requires that the sym->assoc of selectors is set already. */ + gfc_current_ns = ns; + gfc_resolve_blocks (code->block, gfc_current_ns); + gfc_current_ns = old_ns; + + if (ref) + free (ref); +} + + +/* Resolve a SELECT RANK statement. */ + +static void +resolve_select_rank (gfc_code *code, gfc_namespace *old_ns) +{ + gfc_namespace *ns; + gfc_code *body, *new_st, *tail; + gfc_case *c; + char tname[GFC_MAX_SYMBOL_LEN + 7]; + char name[2 * GFC_MAX_SYMBOL_LEN]; + gfc_symtree *st; + gfc_expr *selector_expr = NULL; + int case_value; + HOST_WIDE_INT charlen = 0; + + ns = code->ext.block.ns; + gfc_resolve (ns); + + code->op = EXEC_BLOCK; + if (code->expr2) + { + gfc_association_list* assoc; + + assoc = gfc_get_association_list (); + assoc->st = code->expr1->symtree; + assoc->target = gfc_copy_expr (code->expr2); + assoc->target->where = code->expr2->where; + /* assoc->variable will be set by resolve_assoc_var. */ + + code->ext.block.assoc = assoc; + code->expr1->symtree->n.sym->assoc = assoc; + + resolve_assoc_var (code->expr1->symtree->n.sym, false); + } + else + code->ext.block.assoc = NULL; + + /* Loop over RANK cases. Note that returning on the errors causes a + cascade of further errors because the case blocks do not compile + correctly. */ + for (body = code->block; body; body = body->block) + { + c = body->ext.block.case_list; + if (c->low) + case_value = (int) mpz_get_si (c->low->value.integer); + else + case_value = -2; + + /* Check for repeated cases. */ + for (tail = code->block; tail; tail = tail->block) + { + gfc_case *d = tail->ext.block.case_list; + int case_value2; + + if (tail == body) + break; + + /* Check F2018: C1153. */ + if (!c->low && !d->low) + gfc_error ("RANK DEFAULT at %L is repeated at %L", + &c->where, &d->where); + + if (!c->low || !d->low) + continue; + + /* Check F2018: C1153. */ + case_value2 = (int) mpz_get_si (d->low->value.integer); + if ((case_value == case_value2) && case_value == -1) + gfc_error ("RANK (*) at %L is repeated at %L", + &c->where, &d->where); + else if (case_value == case_value2) + gfc_error ("RANK (%i) at %L is repeated at %L", + case_value, &c->where, &d->where); + } + + if (!c->low) + continue; + + /* Check F2018: C1155. */ + if (case_value == -1 && (gfc_expr_attr (code->expr1).allocatable + || gfc_expr_attr (code->expr1).pointer)) + gfc_error ("RANK (*) at %L cannot be used with the pointer or " + "allocatable selector at %L", &c->where, &code->expr1->where); + + if (case_value == -1 && (gfc_expr_attr (code->expr1).allocatable + || gfc_expr_attr (code->expr1).pointer)) + gfc_error ("RANK (*) at %L cannot be used with the pointer or " + "allocatable selector at %L", &c->where, &code->expr1->where); + } + + /* Add EXEC_SELECT to switch on rank. */ + new_st = gfc_get_code (code->op); + new_st->expr1 = code->expr1; + new_st->expr2 = code->expr2; + new_st->block = code->block; + code->expr1 = code->expr2 = NULL; + code->block = NULL; + if (!ns->code) + ns->code = new_st; + else + ns->code->next = new_st; + code = new_st; + code->op = EXEC_SELECT_RANK; + + selector_expr = code->expr1; + + /* Loop over SELECT RANK cases. */ + for (body = code->block; body; body = body->block) + { + c = body->ext.block.case_list; + int case_value; + + /* Pass on the default case. */ + if (c->low == NULL) + continue; + + /* Associate temporary to selector. This should only be done + when this case is actually true, so build a new ASSOCIATE + that does precisely this here (instead of using the + 'global' one). */ + if (c->ts.type == BT_CHARACTER && c->ts.u.cl && c->ts.u.cl->length + && c->ts.u.cl->length->expr_type == EXPR_CONSTANT) + charlen = gfc_mpz_get_hwi (c->ts.u.cl->length->value.integer); + + if (c->ts.type == BT_CLASS) + sprintf (tname, "class_%s", c->ts.u.derived->name); + else if (c->ts.type == BT_DERIVED) + sprintf (tname, "type_%s", c->ts.u.derived->name); + else if (c->ts.type != BT_CHARACTER) + sprintf (tname, "%s_%d", gfc_basic_typename (c->ts.type), c->ts.kind); + else + sprintf (tname, "%s_" HOST_WIDE_INT_PRINT_DEC "_%d", + gfc_basic_typename (c->ts.type), charlen, c->ts.kind); + + case_value = (int) mpz_get_si (c->low->value.integer); + if (case_value >= 0) + sprintf (name, "__tmp_%s_rank_%d", tname, case_value); + else + sprintf (name, "__tmp_%s_rank_m%d", tname, -case_value); + + st = gfc_find_symtree (ns->sym_root, name); + gcc_assert (st->n.sym->assoc); + + st->n.sym->assoc->target = gfc_get_variable_expr (selector_expr->symtree); + st->n.sym->assoc->target->where = selector_expr->where; + + new_st = gfc_get_code (EXEC_BLOCK); + new_st->ext.block.ns = gfc_build_block_ns (ns); + new_st->ext.block.ns->code = body->next; + body->next = new_st; + + /* Chain in the new list only if it is marked as dangling. Otherwise + there is a CASE label overlap and this is already used. Just ignore, + the error is diagnosed elsewhere. */ + if (st->n.sym->assoc->dangling) + { + new_st->ext.block.assoc = st->n.sym->assoc; + st->n.sym->assoc->dangling = 0; + } + + resolve_assoc_var (st->n.sym, false); + } + + gfc_current_ns = ns; + gfc_resolve_blocks (code->block, gfc_current_ns); + gfc_current_ns = old_ns; +} + + +/* Resolve a transfer statement. This is making sure that: + -- a derived type being transferred has only non-pointer components + -- a derived type being transferred doesn't have private components, unless + it's being transferred from the module where the type was defined + -- we're not trying to transfer a whole assumed size array. */ + +static void +resolve_transfer (gfc_code *code) +{ + gfc_symbol *sym, *derived; + gfc_ref *ref; + gfc_expr *exp; + bool write = false; + bool formatted = false; + gfc_dt *dt = code->ext.dt; + gfc_symbol *dtio_sub = NULL; + + exp = code->expr1; + + while (exp != NULL && exp->expr_type == EXPR_OP + && exp->value.op.op == INTRINSIC_PARENTHESES) + exp = exp->value.op.op1; + + if (exp && exp->expr_type == EXPR_NULL + && code->ext.dt) + { + gfc_error ("Invalid context for NULL () intrinsic at %L", + &exp->where); + return; + } + + if (exp == NULL || (exp->expr_type != EXPR_VARIABLE + && exp->expr_type != EXPR_FUNCTION + && exp->expr_type != EXPR_STRUCTURE)) + return; + + /* If we are reading, the variable will be changed. Note that + code->ext.dt may be NULL if the TRANSFER is related to + an INQUIRE statement -- but in this case, we are not reading, either. */ + if (dt && dt->dt_io_kind->value.iokind == M_READ + && !gfc_check_vardef_context (exp, false, false, false, + _("item in READ"))) + return; + + const gfc_typespec *ts = exp->expr_type == EXPR_STRUCTURE + || exp->expr_type == EXPR_FUNCTION + ? &exp->ts : &exp->symtree->n.sym->ts; + + /* Go to actual component transferred. */ + for (ref = exp->ref; ref; ref = ref->next) + if (ref->type == REF_COMPONENT) + ts = &ref->u.c.component->ts; + + if (dt && dt->dt_io_kind->value.iokind != M_INQUIRE + && (ts->type == BT_DERIVED || ts->type == BT_CLASS)) + { + derived = ts->u.derived; + + /* Determine when to use the formatted DTIO procedure. */ + if (dt && (dt->format_expr || dt->format_label)) + formatted = true; + + write = dt->dt_io_kind->value.iokind == M_WRITE + || dt->dt_io_kind->value.iokind == M_PRINT; + dtio_sub = gfc_find_specific_dtio_proc (derived, write, formatted); + + if (dtio_sub != NULL && exp->expr_type == EXPR_VARIABLE) + { + dt->udtio = exp; + sym = exp->symtree->n.sym->ns->proc_name; + /* Check to see if this is a nested DTIO call, with the + dummy as the io-list object. */ + if (sym && sym == dtio_sub && sym->formal + && sym->formal->sym == exp->symtree->n.sym + && exp->ref == NULL) + { + if (!sym->attr.recursive) + { + gfc_error ("DTIO %s procedure at %L must be recursive", + sym->name, &sym->declared_at); + return; + } + } + } + } + + if (ts->type == BT_CLASS && dtio_sub == NULL) + { + gfc_error ("Data transfer element at %L cannot be polymorphic unless " + "it is processed by a defined input/output procedure", + &code->loc); + return; + } + + if (ts->type == BT_DERIVED) + { + /* Check that transferred derived type doesn't contain POINTER + components unless it is processed by a defined input/output + procedure". */ + if (ts->u.derived->attr.pointer_comp && dtio_sub == NULL) + { + gfc_error ("Data transfer element at %L cannot have POINTER " + "components unless it is processed by a defined " + "input/output procedure", &code->loc); + return; + } + + /* F08:C935. */ + if (ts->u.derived->attr.proc_pointer_comp) + { + gfc_error ("Data transfer element at %L cannot have " + "procedure pointer components", &code->loc); + return; + } + + if (ts->u.derived->attr.alloc_comp && dtio_sub == NULL) + { + gfc_error ("Data transfer element at %L cannot have ALLOCATABLE " + "components unless it is processed by a defined " + "input/output procedure", &code->loc); + return; + } + + /* C_PTR and C_FUNPTR have private components which means they cannot + be printed. However, if -std=gnu and not -pedantic, allow + the component to be printed to help debugging. */ + if (ts->u.derived->ts.f90_type == BT_VOID) + { + if (!gfc_notify_std (GFC_STD_GNU, "Data transfer element at %L " + "cannot have PRIVATE components", &code->loc)) + return; + } + else if (derived_inaccessible (ts->u.derived) && dtio_sub == NULL) + { + gfc_error ("Data transfer element at %L cannot have " + "PRIVATE components unless it is processed by " + "a defined input/output procedure", &code->loc); + return; + } + } + + if (exp->expr_type == EXPR_STRUCTURE) + return; + + sym = exp->symtree->n.sym; + + if (sym->as != NULL && sym->as->type == AS_ASSUMED_SIZE && exp->ref + && exp->ref->type == REF_ARRAY && exp->ref->u.ar.type == AR_FULL) + { + gfc_error ("Data transfer element at %L cannot be a full reference to " + "an assumed-size array", &code->loc); + return; + } +} + + +/*********** Toplevel code resolution subroutines ***********/ + +/* Find the set of labels that are reachable from this block. We also + record the last statement in each block. */ + +static void +find_reachable_labels (gfc_code *block) +{ + gfc_code *c; + + if (!block) + return; + + cs_base->reachable_labels = bitmap_alloc (&labels_obstack); + + /* Collect labels in this block. We don't keep those corresponding + to END {IF|SELECT}, these are checked in resolve_branch by going + up through the code_stack. */ + for (c = block; c; c = c->next) + { + if (c->here && c->op != EXEC_END_NESTED_BLOCK) + bitmap_set_bit (cs_base->reachable_labels, c->here->value); + } + + /* Merge with labels from parent block. */ + if (cs_base->prev) + { + gcc_assert (cs_base->prev->reachable_labels); + bitmap_ior_into (cs_base->reachable_labels, + cs_base->prev->reachable_labels); + } +} + + +static void +resolve_lock_unlock_event (gfc_code *code) +{ + if (code->expr1->expr_type == EXPR_FUNCTION + && code->expr1->value.function.isym + && code->expr1->value.function.isym->id == GFC_ISYM_CAF_GET) + remove_caf_get_intrinsic (code->expr1); + + if ((code->op == EXEC_LOCK || code->op == EXEC_UNLOCK) + && (code->expr1->ts.type != BT_DERIVED + || code->expr1->expr_type != EXPR_VARIABLE + || code->expr1->ts.u.derived->from_intmod != INTMOD_ISO_FORTRAN_ENV + || code->expr1->ts.u.derived->intmod_sym_id != ISOFORTRAN_LOCK_TYPE + || code->expr1->rank != 0 + || (!gfc_is_coarray (code->expr1) && + !gfc_is_coindexed (code->expr1)))) + gfc_error ("Lock variable at %L must be a scalar of type LOCK_TYPE", + &code->expr1->where); + else if ((code->op == EXEC_EVENT_POST || code->op == EXEC_EVENT_WAIT) + && (code->expr1->ts.type != BT_DERIVED + || code->expr1->expr_type != EXPR_VARIABLE + || code->expr1->ts.u.derived->from_intmod + != INTMOD_ISO_FORTRAN_ENV + || code->expr1->ts.u.derived->intmod_sym_id + != ISOFORTRAN_EVENT_TYPE + || code->expr1->rank != 0)) + gfc_error ("Event variable at %L must be a scalar of type EVENT_TYPE", + &code->expr1->where); + else if (code->op == EXEC_EVENT_POST && !gfc_is_coarray (code->expr1) + && !gfc_is_coindexed (code->expr1)) + gfc_error ("Event variable argument at %L must be a coarray or coindexed", + &code->expr1->where); + else if (code->op == EXEC_EVENT_WAIT && !gfc_is_coarray (code->expr1)) + gfc_error ("Event variable argument at %L must be a coarray but not " + "coindexed", &code->expr1->where); + + /* Check STAT. */ + if (code->expr2 + && (code->expr2->ts.type != BT_INTEGER || code->expr2->rank != 0 + || code->expr2->expr_type != EXPR_VARIABLE)) + gfc_error ("STAT= argument at %L must be a scalar INTEGER variable", + &code->expr2->where); + + if (code->expr2 + && !gfc_check_vardef_context (code->expr2, false, false, false, + _("STAT variable"))) + return; + + /* Check ERRMSG. */ + if (code->expr3 + && (code->expr3->ts.type != BT_CHARACTER || code->expr3->rank != 0 + || code->expr3->expr_type != EXPR_VARIABLE)) + gfc_error ("ERRMSG= argument at %L must be a scalar CHARACTER variable", + &code->expr3->where); + + if (code->expr3 + && !gfc_check_vardef_context (code->expr3, false, false, false, + _("ERRMSG variable"))) + return; + + /* Check for LOCK the ACQUIRED_LOCK. */ + if (code->op != EXEC_EVENT_WAIT && code->expr4 + && (code->expr4->ts.type != BT_LOGICAL || code->expr4->rank != 0 + || code->expr4->expr_type != EXPR_VARIABLE)) + gfc_error ("ACQUIRED_LOCK= argument at %L must be a scalar LOGICAL " + "variable", &code->expr4->where); + + if (code->op != EXEC_EVENT_WAIT && code->expr4 + && !gfc_check_vardef_context (code->expr4, false, false, false, + _("ACQUIRED_LOCK variable"))) + return; + + /* Check for EVENT WAIT the UNTIL_COUNT. */ + if (code->op == EXEC_EVENT_WAIT && code->expr4) + { + if (!gfc_resolve_expr (code->expr4) || code->expr4->ts.type != BT_INTEGER + || code->expr4->rank != 0) + gfc_error ("UNTIL_COUNT= argument at %L must be a scalar INTEGER " + "expression", &code->expr4->where); + } +} + + +static void +resolve_critical (gfc_code *code) +{ + gfc_symtree *symtree; + gfc_symbol *lock_type; + char name[GFC_MAX_SYMBOL_LEN]; + static int serial = 0; + + if (flag_coarray != GFC_FCOARRAY_LIB) + return; + + symtree = gfc_find_symtree (gfc_current_ns->sym_root, + GFC_PREFIX ("lock_type")); + if (symtree) + lock_type = symtree->n.sym; + else + { + if (gfc_get_sym_tree (GFC_PREFIX ("lock_type"), gfc_current_ns, &symtree, + false) != 0) + gcc_unreachable (); + lock_type = symtree->n.sym; + lock_type->attr.flavor = FL_DERIVED; + lock_type->attr.zero_comp = 1; + lock_type->from_intmod = INTMOD_ISO_FORTRAN_ENV; + lock_type->intmod_sym_id = ISOFORTRAN_LOCK_TYPE; + } + + sprintf(name, GFC_PREFIX ("lock_var") "%d",serial++); + if (gfc_get_sym_tree (name, gfc_current_ns, &symtree, false) != 0) + gcc_unreachable (); + + code->resolved_sym = symtree->n.sym; + symtree->n.sym->attr.flavor = FL_VARIABLE; + symtree->n.sym->attr.referenced = 1; + symtree->n.sym->attr.artificial = 1; + symtree->n.sym->attr.codimension = 1; + symtree->n.sym->ts.type = BT_DERIVED; + symtree->n.sym->ts.u.derived = lock_type; + symtree->n.sym->as = gfc_get_array_spec (); + symtree->n.sym->as->corank = 1; + symtree->n.sym->as->type = AS_EXPLICIT; + symtree->n.sym->as->cotype = AS_EXPLICIT; + symtree->n.sym->as->lower[0] = gfc_get_int_expr (gfc_default_integer_kind, + NULL, 1); + gfc_commit_symbols(); +} + + +static void +resolve_sync (gfc_code *code) +{ + /* Check imageset. The * case matches expr1 == NULL. */ + if (code->expr1) + { + if (code->expr1->ts.type != BT_INTEGER || code->expr1->rank > 1) + gfc_error ("Imageset argument at %L must be a scalar or rank-1 " + "INTEGER expression", &code->expr1->where); + if (code->expr1->expr_type == EXPR_CONSTANT && code->expr1->rank == 0 + && mpz_cmp_si (code->expr1->value.integer, 1) < 0) + gfc_error ("Imageset argument at %L must between 1 and num_images()", + &code->expr1->where); + else if (code->expr1->expr_type == EXPR_ARRAY + && gfc_simplify_expr (code->expr1, 0)) + { + gfc_constructor *cons; + cons = gfc_constructor_first (code->expr1->value.constructor); + for (; cons; cons = gfc_constructor_next (cons)) + if (cons->expr->expr_type == EXPR_CONSTANT + && mpz_cmp_si (cons->expr->value.integer, 1) < 0) + gfc_error ("Imageset argument at %L must between 1 and " + "num_images()", &cons->expr->where); + } + } + + /* Check STAT. */ + gfc_resolve_expr (code->expr2); + if (code->expr2) + { + if (code->expr2->ts.type != BT_INTEGER || code->expr2->rank != 0) + gfc_error ("STAT= argument at %L must be a scalar INTEGER variable", + &code->expr2->where); + else + gfc_check_vardef_context (code->expr2, false, false, false, + _("STAT variable")); + } + + /* Check ERRMSG. */ + gfc_resolve_expr (code->expr3); + if (code->expr3) + { + if (code->expr3->ts.type != BT_CHARACTER || code->expr3->rank != 0) + gfc_error ("ERRMSG= argument at %L must be a scalar CHARACTER variable", + &code->expr3->where); + else + gfc_check_vardef_context (code->expr3, false, false, false, + _("ERRMSG variable")); + } +} + + +/* Given a branch to a label, see if the branch is conforming. + The code node describes where the branch is located. */ + +static void +resolve_branch (gfc_st_label *label, gfc_code *code) +{ + code_stack *stack; + + if (label == NULL) + return; + + /* Step one: is this a valid branching target? */ + + if (label->defined == ST_LABEL_UNKNOWN) + { + gfc_error ("Label %d referenced at %L is never defined", label->value, + &code->loc); + return; + } + + if (label->defined != ST_LABEL_TARGET && label->defined != ST_LABEL_DO_TARGET) + { + gfc_error ("Statement at %L is not a valid branch target statement " + "for the branch statement at %L", &label->where, &code->loc); + return; + } + + /* Step two: make sure this branch is not a branch to itself ;-) */ + + if (code->here == label) + { + gfc_warning (0, + "Branch at %L may result in an infinite loop", &code->loc); + return; + } + + /* Step three: See if the label is in the same block as the + branching statement. The hard work has been done by setting up + the bitmap reachable_labels. */ + + if (bitmap_bit_p (cs_base->reachable_labels, label->value)) + { + /* Check now whether there is a CRITICAL construct; if so, check + whether the label is still visible outside of the CRITICAL block, + which is invalid. */ + for (stack = cs_base; stack; stack = stack->prev) + { + if (stack->current->op == EXEC_CRITICAL + && bitmap_bit_p (stack->reachable_labels, label->value)) + gfc_error ("GOTO statement at %L leaves CRITICAL construct for " + "label at %L", &code->loc, &label->where); + else if (stack->current->op == EXEC_DO_CONCURRENT + && bitmap_bit_p (stack->reachable_labels, label->value)) + gfc_error ("GOTO statement at %L leaves DO CONCURRENT construct " + "for label at %L", &code->loc, &label->where); + } + + return; + } + + /* Step four: If we haven't found the label in the bitmap, it may + still be the label of the END of the enclosing block, in which + case we find it by going up the code_stack. */ + + for (stack = cs_base; stack; stack = stack->prev) + { + if (stack->current->next && stack->current->next->here == label) + break; + if (stack->current->op == EXEC_CRITICAL) + { + /* Note: A label at END CRITICAL does not leave the CRITICAL + construct as END CRITICAL is still part of it. */ + gfc_error ("GOTO statement at %L leaves CRITICAL construct for label" + " at %L", &code->loc, &label->where); + return; + } + else if (stack->current->op == EXEC_DO_CONCURRENT) + { + gfc_error ("GOTO statement at %L leaves DO CONCURRENT construct for " + "label at %L", &code->loc, &label->where); + return; + } + } + + if (stack) + { + gcc_assert (stack->current->next->op == EXEC_END_NESTED_BLOCK); + return; + } + + /* The label is not in an enclosing block, so illegal. This was + allowed in Fortran 66, so we allow it as extension. No + further checks are necessary in this case. */ + gfc_notify_std (GFC_STD_LEGACY, "Label at %L is not in the same block " + "as the GOTO statement at %L", &label->where, + &code->loc); + return; +} + + +/* Check whether EXPR1 has the same shape as EXPR2. */ + +static bool +resolve_where_shape (gfc_expr *expr1, gfc_expr *expr2) +{ + mpz_t shape[GFC_MAX_DIMENSIONS]; + mpz_t shape2[GFC_MAX_DIMENSIONS]; + bool result = false; + 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])) + goto ignore; + + if (!gfc_array_dimen_size (expr2, i, &shape2[i])) + 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 = true; + +over: + gfc_clear_shape (shape, i); + gfc_clear_shape (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->expr1; + else /* inner WHERE */ + e = mask; + + while (cblock) + { + if (cblock->expr1) + { + /* Check if the mask-expr has a consistent shape with the + outmost WHERE mask-expr. */ + if (!resolve_where_shape (cblock->expr1, e)) + gfc_error ("WHERE mask at %L has inconsistent shape", + &cblock->expr1->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->expr1, e)) + gfc_error ("WHERE assignment target at %L has " + "inconsistent shape", &cnext->expr1->where); + break; + + + case EXEC_ASSIGN_CALL: + resolve_call (cnext); + if (!cnext->resolved_sym->attr.elemental) + gfc_error("Non-ELEMENTAL user-defined assignment in WHERE at %L", + &cnext->ext.actual->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; + } +} + + +/* 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->expr1->expr_type == EXPR_VARIABLE) + && (code->expr1->symtree->n.sym == forall_index)) + gfc_error ("Assignment to a FORALL index variable at %L", + &code->expr1->where); + else + { + /* If one of the FORALL index variables doesn't appear in the + assignment variable, then there could be a many-to-one + assignment. Emit a warning rather than an error because the + mask could be resolving this problem. */ + if (!find_forall_index (code->expr1, forall_index, 0)) + gfc_warning (0, "The FORALL with index %qs is not used on the " + "left side of the assignment at %L and so might " + "cause multiple assignment to this object", + var_expr[n]->symtree->name, &code->expr1->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 operator assignment statement */ + case EXEC_ASSIGN_CALL: + resolve_call (cnext); + if (!cnext->resolved_sym->attr.elemental) + gfc_error("Non-ELEMENTAL user-defined assignment in WHERE at %L", + &cnext->ext.actual->expr->where); + 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; + + case EXEC_ASSIGN_CALL: + resolve_call (c); + break; + + /* Because the gfc_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; + } +} + + +/* Counts the number of iterators needed inside a forall construct, including + nested forall constructs. This is used to allocate the needed memory + in gfc_resolve_forall. */ + +static int +gfc_count_forall_iterators (gfc_code *code) +{ + int max_iters, sub_iters, current_iters; + gfc_forall_iterator *fa; + + gcc_assert(code->op == EXEC_FORALL); + max_iters = 0; + current_iters = 0; + + for (fa = code->ext.forall_iterator; fa; fa = fa->next) + current_iters ++; + + code = code->block->next; + + while (code) + { + if (code->op == EXEC_FORALL) + { + sub_iters = gfc_count_forall_iterators (code); + if (sub_iters > max_iters) + max_iters = sub_iters; + } + code = code->next; + } + + return current_iters + max_iters; +} + + +/* Given a FORALL construct, first resolve the FORALL iterator, then call + gfc_resolve_forall_body to resolve the FORALL body. */ + +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; + int i, old_nvar, tmp; + gfc_forall_iterator *fa; + + old_nvar = nvar; + + if (!gfc_notify_std (GFC_STD_F2018_OBS, "FORALL construct at %L", &code->loc)) + return; + + /* Start to resolve a FORALL construct */ + if (forall_save == 0) + { + /* Count the total number of FORALL indices in the nested FORALL + construct in order to allocate the VAR_EXPR with proper size. */ + total_var = gfc_count_forall_iterators (code); + + /* Allocate VAR_EXPR with NUMBER_OF_FORALL_INDEX elements. */ + var_expr = XCNEWVEC (gfc_expr *, total_var); + } + + /* The information about FORALL iterator, including FORALL indices start, end + and stride. An outer FORALL indice cannot appear in start, end or stride. */ + for (fa = code->ext.forall_iterator; fa; fa = fa->next) + { + /* Fortran 20008: C738 (R753). */ + if (fa->var->ref && fa->var->ref->type == REF_ARRAY) + { + gfc_error ("FORALL index-name at %L must be a scalar variable " + "of type integer", &fa->var->where); + continue; + } + + /* 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); + + nvar++; + + /* No memory leak. */ + gcc_assert (nvar <= total_var); + } + + /* Resolve the FORALL body. */ + gfc_resolve_forall_body (code, nvar, var_expr); + + /* May call gfc_resolve_forall to resolve the inner FORALL loop. */ + gfc_resolve_blocks (code->block, ns); + + tmp = nvar; + nvar = old_nvar; + /* Free only the VAR_EXPRs allocated in this frame. */ + for (i = nvar; i < tmp; i++) + gfc_free_expr (var_expr[i]); + + if (nvar == 0) + { + /* We are in the outermost FORALL construct. */ + gcc_assert (forall_save == 0); + + /* VAR_EXPR is not needed any more. */ + free (var_expr); + total_var = 0; + } +} + + +/* Resolve a BLOCK construct statement. */ + +static void +resolve_block_construct (gfc_code* code) +{ + /* Resolve the BLOCK's namespace. */ + gfc_resolve (code->ext.block.ns); + + /* For an ASSOCIATE block, the associations (and their targets) are already + resolved during resolve_symbol. */ +} + + +/* Resolve lists of blocks found in IF, SELECT CASE, WHERE, FORALL, GOTO and + DO code nodes. */ + +void +gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) +{ + bool t; + + for (; b; b = b->block) + { + t = gfc_resolve_expr (b->expr1); + if (!gfc_resolve_expr (b->expr2)) + t = false; + + switch (b->op) + { + case EXEC_IF: + if (t && b->expr1 != NULL + && (b->expr1->ts.type != BT_LOGICAL || b->expr1->rank != 0)) + gfc_error ("IF clause at %L requires a scalar LOGICAL expression", + &b->expr1->where); + break; + + case EXEC_WHERE: + if (t + && b->expr1 != NULL + && (b->expr1->ts.type != BT_LOGICAL || b->expr1->rank == 0)) + gfc_error ("WHERE/ELSEWHERE clause at %L requires a LOGICAL array", + &b->expr1->where); + break; + + case EXEC_GOTO: + resolve_branch (b->label1, b); + break; + + case EXEC_BLOCK: + resolve_block_construct (b); + break; + + case EXEC_SELECT: + case EXEC_SELECT_TYPE: + case EXEC_SELECT_RANK: + case EXEC_FORALL: + case EXEC_DO: + case EXEC_DO_WHILE: + case EXEC_DO_CONCURRENT: + case EXEC_CRITICAL: + case EXEC_READ: + case EXEC_WRITE: + case EXEC_IOLENGTH: + case EXEC_WAIT: + break; + + case EXEC_OMP_ATOMIC: + case EXEC_OACC_ATOMIC: + { + /* Verify this before calling gfc_resolve_code, which might + change it. */ + gcc_assert (b->op == EXEC_OMP_ATOMIC + || (b->next && b->next->op == EXEC_ASSIGN)); + } + break; + + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_SERIAL_LOOP: + case EXEC_OACC_SERIAL: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + case EXEC_OACC_ROUTINE: + case EXEC_OMP_CRITICAL: + case EXEC_OMP_DISTRIBUTE: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_DISTRIBUTE_SIMD: + case EXEC_OMP_DO: + case EXEC_OMP_DO_SIMD: + case EXEC_OMP_ERROR: + case EXEC_OMP_LOOP: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_MASTER: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_ORDERED: + case EXEC_OMP_PARALLEL: + case EXEC_OMP_PARALLEL_DO: + case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_PARALLEL_SECTIONS: + case EXEC_OMP_PARALLEL_WORKSHARE: + case EXEC_OMP_SECTIONS: + case EXEC_OMP_SIMD: + case EXEC_OMP_SCOPE: + case EXEC_OMP_SINGLE: + case EXEC_OMP_TARGET: + case EXEC_OMP_TARGET_DATA: + case EXEC_OMP_TARGET_ENTER_DATA: + case EXEC_OMP_TARGET_EXIT_DATA: + case EXEC_OMP_TARGET_PARALLEL: + case EXEC_OMP_TARGET_PARALLEL_DO: + case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_PARALLEL_LOOP: + case EXEC_OMP_TARGET_SIMD: + case EXEC_OMP_TARGET_TEAMS: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_TARGET_TEAMS_LOOP: + case EXEC_OMP_TARGET_UPDATE: + case EXEC_OMP_TASK: + case EXEC_OMP_TASKGROUP: + case EXEC_OMP_TASKLOOP: + case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_TASKWAIT: + case EXEC_OMP_TASKYIELD: + case EXEC_OMP_TEAMS: + case EXEC_OMP_TEAMS_DISTRIBUTE: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TEAMS_LOOP: + case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_WORKSHARE: + break; + + default: + gfc_internal_error ("gfc_resolve_blocks(): Bad block type"); + } + + gfc_resolve_code (b->next, ns); + } +} + + +/* Does everything to resolve an ordinary assignment. Returns true + if this is an interface assignment. */ +static bool +resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) +{ + bool rval = false; + gfc_expr *lhs; + gfc_expr *rhs; + int n; + gfc_ref *ref; + symbol_attribute attr; + + if (gfc_extend_assign (code, ns)) + { + gfc_expr** rhsptr; + + if (code->op == EXEC_ASSIGN_CALL) + { + lhs = code->ext.actual->expr; + rhsptr = &code->ext.actual->next->expr; + } + else + { + gfc_actual_arglist* args; + gfc_typebound_proc* tbp; + + gcc_assert (code->op == EXEC_COMPCALL); + + args = code->expr1->value.compcall.actual; + lhs = args->expr; + rhsptr = &args->next->expr; + + tbp = code->expr1->value.compcall.tbp; + gcc_assert (!tbp->is_generic); + } + + /* Make a temporary rhs when there is a default initializer + and rhs is the same symbol as the lhs. */ + if ((*rhsptr)->expr_type == EXPR_VARIABLE + && (*rhsptr)->symtree->n.sym->ts.type == BT_DERIVED + && gfc_has_default_initializer ((*rhsptr)->symtree->n.sym->ts.u.derived) + && (lhs->symtree->n.sym == (*rhsptr)->symtree->n.sym)) + *rhsptr = gfc_get_parentheses (*rhsptr); + + return true; + } + + lhs = code->expr1; + rhs = code->expr2; + + if ((gfc_numeric_ts (&lhs->ts) || lhs->ts.type == BT_LOGICAL) + && rhs->ts.type == BT_CHARACTER + && (rhs->expr_type != EXPR_CONSTANT || !flag_dec_char_conversions)) + { + /* Use of -fdec-char-conversions allows assignment of character data + to non-character variables. This not permited for nonconstant + strings. */ + gfc_error ("Cannot convert %s to %s at %L", gfc_typename (rhs), + gfc_typename (lhs), &rhs->where); + return false; + } + + /* Handle the case of a BOZ literal on the RHS. */ + if (rhs->ts.type == BT_BOZ) + { + if (gfc_invalid_boz ("BOZ literal constant at %L is neither a DATA " + "statement value nor an actual argument of " + "INT/REAL/DBLE/CMPLX intrinsic subprogram", + &rhs->where)) + return false; + + switch (lhs->ts.type) + { + case BT_INTEGER: + if (!gfc_boz2int (rhs, lhs->ts.kind)) + return false; + break; + case BT_REAL: + if (!gfc_boz2real (rhs, lhs->ts.kind)) + return false; + break; + default: + gfc_error ("Invalid use of BOZ literal constant at %L", &rhs->where); + return false; + } + } + + if (lhs->ts.type == BT_CHARACTER && warn_character_truncation) + { + HOST_WIDE_INT llen = 0, rlen = 0; + if (lhs->ts.u.cl != NULL + && lhs->ts.u.cl->length != NULL + && lhs->ts.u.cl->length->expr_type == EXPR_CONSTANT) + llen = gfc_mpz_get_hwi (lhs->ts.u.cl->length->value.integer); + + if (rhs->expr_type == EXPR_CONSTANT) + rlen = rhs->value.character.length; + + else if (rhs->ts.u.cl != NULL + && rhs->ts.u.cl->length != NULL + && rhs->ts.u.cl->length->expr_type == EXPR_CONSTANT) + rlen = gfc_mpz_get_hwi (rhs->ts.u.cl->length->value.integer); + + if (rlen && llen && rlen > llen) + gfc_warning_now (OPT_Wcharacter_truncation, + "CHARACTER expression will be truncated " + "in assignment (%ld/%ld) at %L", + (long) llen, (long) rlen, &code->loc); + } + + /* Ensure that a vector index expression for the lvalue is evaluated + to a temporary if the lvalue symbol is referenced in it. */ + if (lhs->rank) + { + for (ref = lhs->ref; ref; ref= ref->next) + if (ref->type == REF_ARRAY) + { + for (n = 0; n < ref->u.ar.dimen; n++) + if (ref->u.ar.dimen_type[n] == DIMEN_VECTOR + && gfc_find_sym_in_expr (lhs->symtree->n.sym, + ref->u.ar.start[n])) + ref->u.ar.start[n] + = gfc_get_parentheses (ref->u.ar.start[n]); + } + } + + if (gfc_pure (NULL)) + { + if (lhs->ts.type == BT_DERIVED + && lhs->expr_type == EXPR_VARIABLE + && lhs->ts.u.derived->attr.pointer_comp + && rhs->expr_type == EXPR_VARIABLE + && (gfc_impure_variable (rhs->symtree->n.sym) + || gfc_is_coindexed (rhs))) + { + /* F2008, C1283. */ + if (gfc_is_coindexed (rhs)) + gfc_error ("Coindexed expression at %L is assigned to " + "a derived type variable with a POINTER " + "component in a PURE procedure", + &rhs->where); + else + /* F2008, C1283 (4). */ + gfc_error ("In a pure subprogram an INTENT(IN) dummy argument " + "shall not be used as the expr at %L of an intrinsic " + "assignment statement in which the variable is of a " + "derived type if the derived type has a pointer " + "component at any level of component selection.", + &rhs->where); + return rval; + } + + /* Fortran 2008, C1283. */ + if (gfc_is_coindexed (lhs)) + { + gfc_error ("Assignment to coindexed variable at %L in a PURE " + "procedure", &rhs->where); + return rval; + } + } + + if (gfc_implicit_pure (NULL)) + { + if (lhs->expr_type == EXPR_VARIABLE + && lhs->symtree->n.sym != gfc_current_ns->proc_name + && lhs->symtree->n.sym->ns != gfc_current_ns) + gfc_unset_implicit_pure (NULL); + + if (lhs->ts.type == BT_DERIVED + && lhs->expr_type == EXPR_VARIABLE + && lhs->ts.u.derived->attr.pointer_comp + && rhs->expr_type == EXPR_VARIABLE + && (gfc_impure_variable (rhs->symtree->n.sym) + || gfc_is_coindexed (rhs))) + gfc_unset_implicit_pure (NULL); + + /* Fortran 2008, C1283. */ + if (gfc_is_coindexed (lhs)) + gfc_unset_implicit_pure (NULL); + } + + /* F2008, 7.2.1.2. */ + attr = gfc_expr_attr (lhs); + if (lhs->ts.type == BT_CLASS && attr.allocatable) + { + if (attr.codimension) + { + gfc_error ("Assignment to polymorphic coarray at %L is not " + "permitted", &lhs->where); + return false; + } + if (!gfc_notify_std (GFC_STD_F2008, "Assignment to an allocatable " + "polymorphic variable at %L", &lhs->where)) + return false; + if (!flag_realloc_lhs) + { + gfc_error ("Assignment to an allocatable polymorphic variable at %L " + "requires %<-frealloc-lhs%>", &lhs->where); + return false; + } + } + else if (lhs->ts.type == BT_CLASS) + { + gfc_error ("Nonallocatable variable must not be polymorphic in intrinsic " + "assignment at %L - check that there is a matching specific " + "subroutine for '=' operator", &lhs->where); + return false; + } + + bool lhs_coindexed = gfc_is_coindexed (lhs); + + /* F2008, Section 7.2.1.2. */ + if (lhs_coindexed && gfc_has_ultimate_allocatable (lhs)) + { + gfc_error ("Coindexed variable must not have an allocatable ultimate " + "component in assignment at %L", &lhs->where); + return false; + } + + /* Assign the 'data' of a class object to a derived type. */ + if (lhs->ts.type == BT_DERIVED + && rhs->ts.type == BT_CLASS + && rhs->expr_type != EXPR_ARRAY) + gfc_add_data_component (rhs); + + /* Make sure there is a vtable and, in particular, a _copy for the + rhs type. */ + if (lhs->ts.type == BT_CLASS && rhs->ts.type != BT_CLASS) + gfc_find_vtab (&rhs->ts); + + bool caf_convert_to_send = flag_coarray == GFC_FCOARRAY_LIB + && (lhs_coindexed + || (code->expr2->expr_type == EXPR_FUNCTION + && code->expr2->value.function.isym + && code->expr2->value.function.isym->id == GFC_ISYM_CAF_GET + && (code->expr1->rank == 0 || code->expr2->rank != 0) + && !gfc_expr_attr (rhs).allocatable + && !gfc_has_vector_subscript (rhs))); + + gfc_check_assign (lhs, rhs, 1, !caf_convert_to_send); + + /* Insert a GFC_ISYM_CAF_SEND intrinsic, when the LHS is a coindexed variable. + Additionally, insert this code when the RHS is a CAF as we then use the + GFC_ISYM_CAF_SEND intrinsic just to avoid a temporary; but do not do so if + the LHS is (re)allocatable or has a vector subscript. If the LHS is a + noncoindexed array and the RHS is a coindexed scalar, use the normal code + path. */ + if (caf_convert_to_send) + { + if (code->expr2->expr_type == EXPR_FUNCTION + && code->expr2->value.function.isym + && code->expr2->value.function.isym->id == GFC_ISYM_CAF_GET) + remove_caf_get_intrinsic (code->expr2); + code->op = EXEC_CALL; + gfc_get_sym_tree (GFC_PREFIX ("caf_send"), ns, &code->symtree, true); + code->resolved_sym = code->symtree->n.sym; + code->resolved_sym->attr.flavor = FL_PROCEDURE; + code->resolved_sym->attr.intrinsic = 1; + code->resolved_sym->attr.subroutine = 1; + code->resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_CAF_SEND); + gfc_commit_symbol (code->resolved_sym); + code->ext.actual = gfc_get_actual_arglist (); + code->ext.actual->expr = lhs; + code->ext.actual->next = gfc_get_actual_arglist (); + code->ext.actual->next->expr = rhs; + code->expr1 = NULL; + code->expr2 = NULL; + } + + return false; +} + + +/* Add a component reference onto an expression. */ + +static void +add_comp_ref (gfc_expr *e, gfc_component *c) +{ + gfc_ref **ref; + ref = &(e->ref); + while (*ref) + ref = &((*ref)->next); + *ref = gfc_get_ref (); + (*ref)->type = REF_COMPONENT; + (*ref)->u.c.sym = e->ts.u.derived; + (*ref)->u.c.component = c; + e->ts = c->ts; + + /* Add a full array ref, as necessary. */ + if (c->as) + { + gfc_add_full_array_ref (e, c->as); + e->rank = c->as->rank; + } +} + + +/* Build an assignment. Keep the argument 'op' for future use, so that + pointer assignments can be made. */ + +static gfc_code * +build_assignment (gfc_exec_op op, gfc_expr *expr1, gfc_expr *expr2, + gfc_component *comp1, gfc_component *comp2, locus loc) +{ + gfc_code *this_code; + + this_code = gfc_get_code (op); + this_code->next = NULL; + this_code->expr1 = gfc_copy_expr (expr1); + this_code->expr2 = gfc_copy_expr (expr2); + this_code->loc = loc; + if (comp1 && comp2) + { + add_comp_ref (this_code->expr1, comp1); + add_comp_ref (this_code->expr2, comp2); + } + + return this_code; +} + + +/* Makes a temporary variable expression based on the characteristics of + a given variable expression. */ + +static gfc_expr* +get_temp_from_expr (gfc_expr *e, gfc_namespace *ns) +{ + static int serial = 0; + char name[GFC_MAX_SYMBOL_LEN]; + gfc_symtree *tmp; + gfc_array_spec *as; + gfc_array_ref *aref; + gfc_ref *ref; + + sprintf (name, GFC_PREFIX("DA%d"), serial++); + gfc_get_sym_tree (name, ns, &tmp, false); + gfc_add_type (tmp->n.sym, &e->ts, NULL); + + if (e->expr_type == EXPR_CONSTANT && e->ts.type == BT_CHARACTER) + tmp->n.sym->ts.u.cl->length = gfc_get_int_expr (gfc_charlen_int_kind, + NULL, + e->value.character.length); + + as = NULL; + ref = NULL; + aref = NULL; + + /* Obtain the arrayspec for the temporary. */ + if (e->rank && e->expr_type != EXPR_ARRAY + && e->expr_type != EXPR_FUNCTION + && e->expr_type != EXPR_OP) + { + aref = gfc_find_array_ref (e); + if (e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->as == aref->as) + as = aref->as; + else + { + for (ref = e->ref; ref; ref = ref->next) + if (ref->type == REF_COMPONENT + && ref->u.c.component->as == aref->as) + { + as = aref->as; + break; + } + } + } + + /* Add the attributes and the arrayspec to the temporary. */ + tmp->n.sym->attr = gfc_expr_attr (e); + tmp->n.sym->attr.function = 0; + tmp->n.sym->attr.proc_pointer = 0; + tmp->n.sym->attr.result = 0; + tmp->n.sym->attr.flavor = FL_VARIABLE; + tmp->n.sym->attr.dummy = 0; + tmp->n.sym->attr.use_assoc = 0; + tmp->n.sym->attr.intent = INTENT_UNKNOWN; + + if (as) + { + tmp->n.sym->as = gfc_copy_array_spec (as); + if (!ref) + ref = e->ref; + if (as->type == AS_DEFERRED) + tmp->n.sym->attr.allocatable = 1; + } + else if (e->rank && (e->expr_type == EXPR_ARRAY + || e->expr_type == EXPR_FUNCTION + || e->expr_type == EXPR_OP)) + { + tmp->n.sym->as = gfc_get_array_spec (); + tmp->n.sym->as->type = AS_DEFERRED; + tmp->n.sym->as->rank = e->rank; + tmp->n.sym->attr.allocatable = 1; + tmp->n.sym->attr.dimension = 1; + } + else + tmp->n.sym->attr.dimension = 0; + + gfc_set_sym_referenced (tmp->n.sym); + gfc_commit_symbol (tmp->n.sym); + e = gfc_lval_expr_from_sym (tmp->n.sym); + + /* Should the lhs be a section, use its array ref for the + temporary expression. */ + if (aref && aref->type != AR_FULL) + { + gfc_free_ref_list (e->ref); + e->ref = gfc_copy_ref (ref); + } + return e; +} + + +/* Add one line of code to the code chain, making sure that 'head' and + 'tail' are appropriately updated. */ + +static void +add_code_to_chain (gfc_code **this_code, gfc_code **head, gfc_code **tail) +{ + gcc_assert (this_code); + if (*head == NULL) + *head = *tail = *this_code; + else + *tail = gfc_append_code (*tail, *this_code); + *this_code = NULL; +} + + +/* Counts the potential number of part array references that would + result from resolution of typebound defined assignments. */ + +static int +nonscalar_typebound_assign (gfc_symbol *derived, int depth) +{ + gfc_component *c; + int c_depth = 0, t_depth; + + for (c= derived->components; c; c = c->next) + { + if ((!gfc_bt_struct (c->ts.type) + || c->attr.pointer + || c->attr.allocatable + || c->attr.proc_pointer_comp + || c->attr.class_pointer + || c->attr.proc_pointer) + && !c->attr.defined_assign_comp) + continue; + + if (c->as && c_depth == 0) + c_depth = 1; + + if (c->ts.u.derived->attr.defined_assign_comp) + t_depth = nonscalar_typebound_assign (c->ts.u.derived, + c->as ? 1 : 0); + else + t_depth = 0; + + c_depth = t_depth > c_depth ? t_depth : c_depth; + } + return depth + c_depth; +} + + +/* Implement 7.2.1.3 of the F08 standard: + "An intrinsic assignment where the variable is of derived type is + performed as if each component of the variable were assigned from the + corresponding component of expr using pointer assignment (7.2.2) for + each pointer component, defined assignment for each nonpointer + nonallocatable component of a type that has a type-bound defined + assignment consistent with the component, intrinsic assignment for + each other nonpointer nonallocatable component, ..." + + The pointer assignments are taken care of by the intrinsic + assignment of the structure itself. This function recursively adds + defined assignments where required. The recursion is accomplished + by calling gfc_resolve_code. + + When the lhs in a defined assignment has intent INOUT, we need a + temporary for the lhs. In pseudo-code: + + ! Only call function lhs once. + if (lhs is not a constant or an variable) + temp_x = expr2 + expr2 => temp_x + ! Do the intrinsic assignment + expr1 = expr2 + ! Now do the defined assignments + do over components with typebound defined assignment [%cmp] + #if one component's assignment procedure is INOUT + t1 = expr1 + #if expr2 non-variable + temp_x = expr2 + expr2 => temp_x + # endif + expr1 = expr2 + # for each cmp + t1%cmp {defined=} expr2%cmp + expr1%cmp = t1%cmp + #else + expr1 = expr2 + + # for each cmp + expr1%cmp {defined=} expr2%cmp + #endif + */ + +/* The temporary assignments have to be put on top of the additional + code to avoid the result being changed by the intrinsic assignment. + */ +static int component_assignment_level = 0; +static gfc_code *tmp_head = NULL, *tmp_tail = NULL; + +static void +generate_component_assignments (gfc_code **code, gfc_namespace *ns) +{ + gfc_component *comp1, *comp2; + gfc_code *this_code = NULL, *head = NULL, *tail = NULL; + gfc_expr *t1; + int error_count, depth; + + gfc_get_errors (NULL, &error_count); + + /* Filter out continuing processing after an error. */ + if (error_count + || (*code)->expr1->ts.type != BT_DERIVED + || (*code)->expr2->ts.type != BT_DERIVED) + return; + + /* TODO: Handle more than one part array reference in assignments. */ + depth = nonscalar_typebound_assign ((*code)->expr1->ts.u.derived, + (*code)->expr1->rank ? 1 : 0); + if (depth > 1) + { + gfc_warning (0, "TODO: type-bound defined assignment(s) at %L not " + "done because multiple part array references would " + "occur in intermediate expressions.", &(*code)->loc); + return; + } + + component_assignment_level++; + + /* Create a temporary so that functions get called only once. */ + if ((*code)->expr2->expr_type != EXPR_VARIABLE + && (*code)->expr2->expr_type != EXPR_CONSTANT) + { + gfc_expr *tmp_expr; + + /* Assign the rhs to the temporary. */ + tmp_expr = get_temp_from_expr ((*code)->expr1, ns); + this_code = build_assignment (EXEC_ASSIGN, + tmp_expr, (*code)->expr2, + NULL, NULL, (*code)->loc); + /* Add the code and substitute the rhs expression. */ + add_code_to_chain (&this_code, &tmp_head, &tmp_tail); + gfc_free_expr ((*code)->expr2); + (*code)->expr2 = tmp_expr; + } + + /* Do the intrinsic assignment. This is not needed if the lhs is one + of the temporaries generated here, since the intrinsic assignment + to the final result already does this. */ + if ((*code)->expr1->symtree->n.sym->name[2] != '@') + { + this_code = build_assignment (EXEC_ASSIGN, + (*code)->expr1, (*code)->expr2, + NULL, NULL, (*code)->loc); + add_code_to_chain (&this_code, &head, &tail); + } + + comp1 = (*code)->expr1->ts.u.derived->components; + comp2 = (*code)->expr2->ts.u.derived->components; + + t1 = NULL; + for (; comp1; comp1 = comp1->next, comp2 = comp2->next) + { + bool inout = false; + + /* The intrinsic assignment does the right thing for pointers + of all kinds and allocatable components. */ + if (!gfc_bt_struct (comp1->ts.type) + || comp1->attr.pointer + || comp1->attr.allocatable + || comp1->attr.proc_pointer_comp + || comp1->attr.class_pointer + || comp1->attr.proc_pointer) + continue; + + /* Make an assigment for this component. */ + this_code = build_assignment (EXEC_ASSIGN, + (*code)->expr1, (*code)->expr2, + comp1, comp2, (*code)->loc); + + /* Convert the assignment if there is a defined assignment for + this type. Otherwise, using the call from gfc_resolve_code, + recurse into its components. */ + gfc_resolve_code (this_code, ns); + + if (this_code->op == EXEC_ASSIGN_CALL) + { + gfc_formal_arglist *dummy_args; + gfc_symbol *rsym; + /* Check that there is a typebound defined assignment. If not, + then this must be a module defined assignment. We cannot + use the defined_assign_comp attribute here because it must + be this derived type that has the defined assignment and not + a parent type. */ + if (!(comp1->ts.u.derived->f2k_derived + && comp1->ts.u.derived->f2k_derived + ->tb_op[INTRINSIC_ASSIGN])) + { + gfc_free_statements (this_code); + this_code = NULL; + continue; + } + + /* If the first argument of the subroutine has intent INOUT + a temporary must be generated and used instead. */ + rsym = this_code->resolved_sym; + dummy_args = gfc_sym_get_dummy_args (rsym); + if (dummy_args + && dummy_args->sym->attr.intent == INTENT_INOUT) + { + gfc_code *temp_code; + inout = true; + + /* Build the temporary required for the assignment and put + it at the head of the generated code. */ + if (!t1) + { + t1 = get_temp_from_expr ((*code)->expr1, ns); + temp_code = build_assignment (EXEC_ASSIGN, + t1, (*code)->expr1, + NULL, NULL, (*code)->loc); + + /* For allocatable LHS, check whether it is allocated. Note + that allocatable components with defined assignment are + not yet support. See PR 57696. */ + if ((*code)->expr1->symtree->n.sym->attr.allocatable) + { + gfc_code *block; + gfc_expr *e = + gfc_lval_expr_from_sym ((*code)->expr1->symtree->n.sym); + block = gfc_get_code (EXEC_IF); + block->block = gfc_get_code (EXEC_IF); + block->block->expr1 + = gfc_build_intrinsic_call (ns, + GFC_ISYM_ALLOCATED, "allocated", + (*code)->loc, 1, e); + block->block->next = temp_code; + temp_code = block; + } + add_code_to_chain (&temp_code, &tmp_head, &tmp_tail); + } + + /* Replace the first actual arg with the component of the + temporary. */ + gfc_free_expr (this_code->ext.actual->expr); + this_code->ext.actual->expr = gfc_copy_expr (t1); + add_comp_ref (this_code->ext.actual->expr, comp1); + + /* If the LHS variable is allocatable and wasn't allocated and + the temporary is allocatable, pointer assign the address of + the freshly allocated LHS to the temporary. */ + if ((*code)->expr1->symtree->n.sym->attr.allocatable + && gfc_expr_attr ((*code)->expr1).allocatable) + { + gfc_code *block; + gfc_expr *cond; + + cond = gfc_get_expr (); + cond->ts.type = BT_LOGICAL; + cond->ts.kind = gfc_default_logical_kind; + cond->expr_type = EXPR_OP; + cond->where = (*code)->loc; + cond->value.op.op = INTRINSIC_NOT; + cond->value.op.op1 = gfc_build_intrinsic_call (ns, + GFC_ISYM_ALLOCATED, "allocated", + (*code)->loc, 1, gfc_copy_expr (t1)); + block = gfc_get_code (EXEC_IF); + block->block = gfc_get_code (EXEC_IF); + block->block->expr1 = cond; + block->block->next = build_assignment (EXEC_POINTER_ASSIGN, + t1, (*code)->expr1, + NULL, NULL, (*code)->loc); + add_code_to_chain (&block, &head, &tail); + } + } + } + else if (this_code->op == EXEC_ASSIGN && !this_code->next) + { + /* Don't add intrinsic assignments since they are already + effected by the intrinsic assignment of the structure. */ + gfc_free_statements (this_code); + this_code = NULL; + continue; + } + + add_code_to_chain (&this_code, &head, &tail); + + if (t1 && inout) + { + /* Transfer the value to the final result. */ + this_code = build_assignment (EXEC_ASSIGN, + (*code)->expr1, t1, + comp1, comp2, (*code)->loc); + add_code_to_chain (&this_code, &head, &tail); + } + } + + /* Put the temporary assignments at the top of the generated code. */ + if (tmp_head && component_assignment_level == 1) + { + gfc_append_code (tmp_head, head); + head = tmp_head; + tmp_head = tmp_tail = NULL; + } + + // If we did a pointer assignment - thus, we need to ensure that the LHS is + // not accidentally deallocated. Hence, nullify t1. + if (t1 && (*code)->expr1->symtree->n.sym->attr.allocatable + && gfc_expr_attr ((*code)->expr1).allocatable) + { + gfc_code *block; + gfc_expr *cond; + gfc_expr *e; + + e = gfc_lval_expr_from_sym ((*code)->expr1->symtree->n.sym); + cond = gfc_build_intrinsic_call (ns, GFC_ISYM_ASSOCIATED, "associated", + (*code)->loc, 2, gfc_copy_expr (t1), e); + block = gfc_get_code (EXEC_IF); + block->block = gfc_get_code (EXEC_IF); + block->block->expr1 = cond; + block->block->next = build_assignment (EXEC_POINTER_ASSIGN, + t1, gfc_get_null_expr (&(*code)->loc), + NULL, NULL, (*code)->loc); + gfc_append_code (tail, block); + tail = block; + } + + /* Now attach the remaining code chain to the input code. Step on + to the end of the new code since resolution is complete. */ + gcc_assert ((*code)->op == EXEC_ASSIGN); + tail->next = (*code)->next; + /* Overwrite 'code' because this would place the intrinsic assignment + before the temporary for the lhs is created. */ + gfc_free_expr ((*code)->expr1); + gfc_free_expr ((*code)->expr2); + **code = *head; + if (head != tail) + free (head); + *code = tail; + + component_assignment_level--; +} + + +/* F2008: Pointer function assignments are of the form: + ptr_fcn (args) = expr + This function breaks these assignments into two statements: + temporary_pointer => ptr_fcn(args) + temporary_pointer = expr */ + +static bool +resolve_ptr_fcn_assign (gfc_code **code, gfc_namespace *ns) +{ + gfc_expr *tmp_ptr_expr; + gfc_code *this_code; + gfc_component *comp; + gfc_symbol *s; + + if ((*code)->expr1->expr_type != EXPR_FUNCTION) + return false; + + /* Even if standard does not support this feature, continue to build + the two statements to avoid upsetting frontend_passes.c. */ + gfc_notify_std (GFC_STD_F2008, "Pointer procedure assignment at " + "%L", &(*code)->loc); + + comp = gfc_get_proc_ptr_comp ((*code)->expr1); + + if (comp) + s = comp->ts.interface; + else + s = (*code)->expr1->symtree->n.sym; + + if (s == NULL || !s->result->attr.pointer) + { + gfc_error ("The function result on the lhs of the assignment at " + "%L must have the pointer attribute.", + &(*code)->expr1->where); + (*code)->op = EXEC_NOP; + return false; + } + + tmp_ptr_expr = get_temp_from_expr ((*code)->expr1, ns); + + /* get_temp_from_expression is set up for ordinary assignments. To that + end, where array bounds are not known, arrays are made allocatable. + Change the temporary to a pointer here. */ + tmp_ptr_expr->symtree->n.sym->attr.pointer = 1; + tmp_ptr_expr->symtree->n.sym->attr.allocatable = 0; + tmp_ptr_expr->where = (*code)->loc; + + this_code = build_assignment (EXEC_ASSIGN, + tmp_ptr_expr, (*code)->expr2, + NULL, NULL, (*code)->loc); + this_code->next = (*code)->next; + (*code)->next = this_code; + (*code)->op = EXEC_POINTER_ASSIGN; + (*code)->expr2 = (*code)->expr1; + (*code)->expr1 = tmp_ptr_expr; + + return true; +} + + +/* Deferred character length assignments from an operator expression + require a temporary because the character length of the lhs can + change in the course of the assignment. */ + +static bool +deferred_op_assign (gfc_code **code, gfc_namespace *ns) +{ + gfc_expr *tmp_expr; + gfc_code *this_code; + + if (!((*code)->expr1->ts.type == BT_CHARACTER + && (*code)->expr1->ts.deferred && (*code)->expr1->rank + && (*code)->expr2->expr_type == EXPR_OP)) + return false; + + if (!gfc_check_dependency ((*code)->expr1, (*code)->expr2, 1)) + return false; + + if (gfc_expr_attr ((*code)->expr1).pointer) + return false; + + tmp_expr = get_temp_from_expr ((*code)->expr1, ns); + tmp_expr->where = (*code)->loc; + + /* A new charlen is required to ensure that the variable string + length is different to that of the original lhs. */ + tmp_expr->ts.u.cl = gfc_get_charlen(); + tmp_expr->symtree->n.sym->ts.u.cl = tmp_expr->ts.u.cl; + tmp_expr->ts.u.cl->next = (*code)->expr2->ts.u.cl->next; + (*code)->expr2->ts.u.cl->next = tmp_expr->ts.u.cl; + + tmp_expr->symtree->n.sym->ts.deferred = 1; + + this_code = build_assignment (EXEC_ASSIGN, + (*code)->expr1, + gfc_copy_expr (tmp_expr), + NULL, NULL, (*code)->loc); + + (*code)->expr1 = tmp_expr; + + this_code->next = (*code)->next; + (*code)->next = this_code; + + return true; +} + + +/* Given a block of code, recursively resolve everything pointed to by this + code block. */ + +void +gfc_resolve_code (gfc_code *code, gfc_namespace *ns) +{ + int omp_workshare_save; + int forall_save, do_concurrent_save; + code_stack frame; + bool t; + + frame.prev = cs_base; + frame.head = code; + cs_base = &frame; + + find_reachable_labels (code); + + for (; code; code = code->next) + { + frame.current = code; + forall_save = forall_flag; + do_concurrent_save = gfc_do_concurrent_flag; + + if (code->op == EXEC_FORALL) + { + forall_flag = 1; + gfc_resolve_forall (code, ns, forall_save); + forall_flag = 2; + } + else if (code->block) + { + omp_workshare_save = -1; + switch (code->op) + { + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_SERIAL_LOOP: + case EXEC_OACC_SERIAL: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + gfc_resolve_oacc_blocks (code, ns); + break; + case EXEC_OMP_PARALLEL_WORKSHARE: + omp_workshare_save = omp_workshare_flag; + omp_workshare_flag = 1; + gfc_resolve_omp_parallel_blocks (code, ns); + break; + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL: + case EXEC_OMP_PARALLEL_DO: + case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_PARALLEL_SECTIONS: + case EXEC_OMP_TARGET_PARALLEL: + case EXEC_OMP_TARGET_PARALLEL_DO: + case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_TEAMS: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_TASK: + case EXEC_OMP_TASKLOOP: + case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_TEAMS: + case EXEC_OMP_TEAMS_DISTRIBUTE: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD: + omp_workshare_save = omp_workshare_flag; + omp_workshare_flag = 0; + gfc_resolve_omp_parallel_blocks (code, ns); + break; + case EXEC_OMP_DISTRIBUTE: + case EXEC_OMP_DISTRIBUTE_SIMD: + case EXEC_OMP_DO: + case EXEC_OMP_DO_SIMD: + case EXEC_OMP_SIMD: + case EXEC_OMP_TARGET_SIMD: + gfc_resolve_omp_do_blocks (code, ns); + break; + case EXEC_SELECT_TYPE: + case EXEC_SELECT_RANK: + /* Blocks are handled in resolve_select_type/rank because we + have to transform the SELECT TYPE into ASSOCIATE first. */ + break; + case EXEC_DO_CONCURRENT: + gfc_do_concurrent_flag = 1; + gfc_resolve_blocks (code->block, ns); + gfc_do_concurrent_flag = 2; + break; + case EXEC_OMP_WORKSHARE: + omp_workshare_save = omp_workshare_flag; + omp_workshare_flag = 1; + /* FALL THROUGH */ + default: + gfc_resolve_blocks (code->block, ns); + break; + } + + if (omp_workshare_save != -1) + omp_workshare_flag = omp_workshare_save; + } +start: + t = true; + if (code->op != EXEC_COMPCALL && code->op != EXEC_CALL_PPC) + t = gfc_resolve_expr (code->expr1); + forall_flag = forall_save; + gfc_do_concurrent_flag = do_concurrent_save; + + if (!gfc_resolve_expr (code->expr2)) + t = false; + + if (code->op == EXEC_ALLOCATE + && !gfc_resolve_expr (code->expr3)) + t = false; + + switch (code->op) + { + case EXEC_NOP: + case EXEC_END_BLOCK: + case EXEC_END_NESTED_BLOCK: + case EXEC_CYCLE: + case EXEC_PAUSE: + case EXEC_STOP: + case EXEC_ERROR_STOP: + case EXEC_EXIT: + case EXEC_CONTINUE: + case EXEC_DT_END: + case EXEC_ASSIGN_CALL: + break; + + case EXEC_CRITICAL: + resolve_critical (code); + break; + + case EXEC_SYNC_ALL: + case EXEC_SYNC_IMAGES: + case EXEC_SYNC_MEMORY: + resolve_sync (code); + break; + + case EXEC_LOCK: + case EXEC_UNLOCK: + case EXEC_EVENT_POST: + case EXEC_EVENT_WAIT: + resolve_lock_unlock_event (code); + break; + + case EXEC_FAIL_IMAGE: + case EXEC_FORM_TEAM: + case EXEC_CHANGE_TEAM: + case EXEC_END_TEAM: + case EXEC_SYNC_TEAM: + break; + + case EXEC_ENTRY: + /* Keep track of which entry we are up to. */ + current_entry_id = code->ext.entry->id; + break; + + case EXEC_WHERE: + resolve_where (code, NULL); + break; + + case EXEC_GOTO: + if (code->expr1 != NULL) + { + if (code->expr1->expr_type != EXPR_VARIABLE + || code->expr1->ts.type != BT_INTEGER + || (code->expr1->ref + && code->expr1->ref->type == REF_ARRAY) + || code->expr1->symtree == NULL + || (code->expr1->symtree->n.sym + && (code->expr1->symtree->n.sym->attr.flavor + == FL_PARAMETER))) + gfc_error ("ASSIGNED GOTO statement at %L requires a " + "scalar INTEGER variable", &code->expr1->where); + else if (code->expr1->symtree->n.sym + && code->expr1->symtree->n.sym->attr.assign != 1) + gfc_error ("Variable %qs has not been assigned a target " + "label at %L", code->expr1->symtree->n.sym->name, + &code->expr1->where); + } + else + resolve_branch (code->label1, code); + break; + + case EXEC_RETURN: + if (code->expr1 != NULL + && (code->expr1->ts.type != BT_INTEGER || code->expr1->rank)) + gfc_error ("Alternate RETURN statement at %L requires a SCALAR-" + "INTEGER return specifier", &code->expr1->where); + break; + + case EXEC_INIT_ASSIGN: + case EXEC_END_PROCEDURE: + break; + + case EXEC_ASSIGN: + if (!t) + break; + + if (code->expr1->ts.type == BT_CLASS) + gfc_find_vtab (&code->expr2->ts); + + /* Remove a GFC_ISYM_CAF_GET inserted for a coindexed variable on + the LHS. */ + if (code->expr1->expr_type == EXPR_FUNCTION + && code->expr1->value.function.isym + && code->expr1->value.function.isym->id == GFC_ISYM_CAF_GET) + remove_caf_get_intrinsic (code->expr1); + + /* If this is a pointer function in an lvalue variable context, + the new code will have to be resolved afresh. This is also the + case with an error, where the code is transformed into NOP to + prevent ICEs downstream. */ + if (resolve_ptr_fcn_assign (&code, ns) + || code->op == EXEC_NOP) + goto start; + + if (!gfc_check_vardef_context (code->expr1, false, false, false, + _("assignment"))) + break; + + if (resolve_ordinary_assign (code, ns)) + { + if (omp_workshare_flag) + { + gfc_error ("Expected intrinsic assignment in OMP WORKSHARE " + "at %L", &code->loc); + break; + } + if (code->op == EXEC_COMPCALL) + goto compcall; + else + goto call; + } + + /* Check for dependencies in deferred character length array + assignments and generate a temporary, if necessary. */ + if (code->op == EXEC_ASSIGN && deferred_op_assign (&code, ns)) + break; + + /* F03 7.4.1.3 for non-allocatable, non-pointer components. */ + if (code->op != EXEC_CALL && code->expr1->ts.type == BT_DERIVED + && code->expr1->ts.u.derived + && code->expr1->ts.u.derived->attr.defined_assign_comp) + generate_component_assignments (&code, ns); + + break; + + case EXEC_LABEL_ASSIGN: + if (code->label1->defined == ST_LABEL_UNKNOWN) + gfc_error ("Label %d referenced at %L is never defined", + code->label1->value, &code->label1->where); + if (t + && (code->expr1->expr_type != EXPR_VARIABLE + || code->expr1->symtree->n.sym->ts.type != BT_INTEGER + || code->expr1->symtree->n.sym->ts.kind + != gfc_default_integer_kind + || code->expr1->symtree->n.sym->attr.flavor == FL_PARAMETER + || code->expr1->symtree->n.sym->as != NULL)) + gfc_error ("ASSIGN statement at %L requires a scalar " + "default INTEGER variable", &code->expr1->where); + break; + + case EXEC_POINTER_ASSIGN: + { + gfc_expr* e; + + if (!t) + break; + + /* This is both a variable definition and pointer assignment + context, so check both of them. For rank remapping, a final + array ref may be present on the LHS and fool gfc_expr_attr + used in gfc_check_vardef_context. Remove it. */ + e = remove_last_array_ref (code->expr1); + t = gfc_check_vardef_context (e, true, false, false, + _("pointer assignment")); + if (t) + t = gfc_check_vardef_context (e, false, false, false, + _("pointer assignment")); + gfc_free_expr (e); + + t = gfc_check_pointer_assign (code->expr1, code->expr2, !t) && t; + + if (!t) + break; + + /* Assigning a class object always is a regular assign. */ + if (code->expr2->ts.type == BT_CLASS + && code->expr1->ts.type == BT_CLASS + && CLASS_DATA (code->expr2) + && !CLASS_DATA (code->expr2)->attr.dimension + && !(gfc_expr_attr (code->expr1).proc_pointer + && code->expr2->expr_type == EXPR_VARIABLE + && code->expr2->symtree->n.sym->attr.flavor + == FL_PROCEDURE)) + code->op = EXEC_ASSIGN; + break; + } + + case EXEC_ARITHMETIC_IF: + { + gfc_expr *e = code->expr1; + + gfc_resolve_expr (e); + if (e->expr_type == EXPR_NULL) + gfc_error ("Invalid NULL at %L", &e->where); + + if (t && (e->rank > 0 + || !(e->ts.type == BT_REAL || e->ts.type == BT_INTEGER))) + gfc_error ("Arithmetic IF statement at %L requires a scalar " + "REAL or INTEGER expression", &e->where); + + resolve_branch (code->label1, code); + resolve_branch (code->label2, code); + resolve_branch (code->label3, code); + } + break; + + case EXEC_IF: + if (t && code->expr1 != NULL + && (code->expr1->ts.type != BT_LOGICAL + || code->expr1->rank != 0)) + gfc_error ("IF clause at %L requires a scalar LOGICAL expression", + &code->expr1->where); + break; + + case EXEC_CALL: + call: + resolve_call (code); + break; + + case EXEC_COMPCALL: + compcall: + resolve_typebound_subroutine (code); + break; + + case EXEC_CALL_PPC: + resolve_ppc_call (code); + break; + + case EXEC_SELECT: + /* Select is complicated. Also, a SELECT construct could be + a transformed computed GOTO. */ + resolve_select (code, false); + break; + + case EXEC_SELECT_TYPE: + resolve_select_type (code, ns); + break; + + case EXEC_SELECT_RANK: + resolve_select_rank (code, ns); + break; + + case EXEC_BLOCK: + resolve_block_construct (code); + break; + + case EXEC_DO: + if (code->ext.iterator != NULL) + { + gfc_iterator *iter = code->ext.iterator; + if (gfc_resolve_iterator (iter, true, false)) + gfc_resolve_do_iterator (code, iter->var->symtree->n.sym, + true); + } + break; + + case EXEC_DO_WHILE: + if (code->expr1 == NULL) + gfc_internal_error ("gfc_resolve_code(): No expression on " + "DO WHILE"); + if (t + && (code->expr1->rank != 0 + || code->expr1->ts.type != BT_LOGICAL)) + gfc_error ("Exit condition of DO WHILE loop at %L must be " + "a scalar LOGICAL expression", &code->expr1->where); + break; + + case EXEC_ALLOCATE: + if (t) + resolve_allocate_deallocate (code, "ALLOCATE"); + + break; + + case EXEC_DEALLOCATE: + if (t) + resolve_allocate_deallocate (code, "DEALLOCATE"); + + break; + + case EXEC_OPEN: + if (!gfc_resolve_open (code->ext.open, &code->loc)) + break; + + resolve_branch (code->ext.open->err, code); + break; + + case EXEC_CLOSE: + if (!gfc_resolve_close (code->ext.close, &code->loc)) + break; + + resolve_branch (code->ext.close->err, code); + break; + + case EXEC_BACKSPACE: + case EXEC_ENDFILE: + case EXEC_REWIND: + case EXEC_FLUSH: + if (!gfc_resolve_filepos (code->ext.filepos, &code->loc)) + break; + + resolve_branch (code->ext.filepos->err, code); + break; + + case EXEC_INQUIRE: + if (!gfc_resolve_inquire (code->ext.inquire)) + break; + + resolve_branch (code->ext.inquire->err, code); + break; + + case EXEC_IOLENGTH: + gcc_assert (code->ext.inquire != NULL); + if (!gfc_resolve_inquire (code->ext.inquire)) + break; + + resolve_branch (code->ext.inquire->err, code); + break; + + case EXEC_WAIT: + if (!gfc_resolve_wait (code->ext.wait)) + break; + + resolve_branch (code->ext.wait->err, code); + resolve_branch (code->ext.wait->end, code); + resolve_branch (code->ext.wait->eor, code); + break; + + case EXEC_READ: + case EXEC_WRITE: + if (!gfc_resolve_dt (code, code->ext.dt, &code->loc)) + 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_TRANSFER: + resolve_transfer (code); + break; + + case EXEC_DO_CONCURRENT: + case EXEC_FORALL: + resolve_forall_iterators (code->ext.forall_iterator); + + if (code->expr1 != NULL + && (code->expr1->ts.type != BT_LOGICAL || code->expr1->rank)) + gfc_error ("FORALL mask clause at %L requires a scalar LOGICAL " + "expression", &code->expr1->where); + break; + + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_SERIAL_LOOP: + case EXEC_OACC_SERIAL: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + case EXEC_OACC_ATOMIC: + case EXEC_OACC_DECLARE: + gfc_resolve_oacc_directive (code, ns); + break; + + case EXEC_OMP_ATOMIC: + case EXEC_OMP_BARRIER: + case EXEC_OMP_CANCEL: + case EXEC_OMP_CANCELLATION_POINT: + case EXEC_OMP_CRITICAL: + case EXEC_OMP_FLUSH: + case EXEC_OMP_DEPOBJ: + case EXEC_OMP_DISTRIBUTE: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_DISTRIBUTE_SIMD: + case EXEC_OMP_DO: + case EXEC_OMP_DO_SIMD: + case EXEC_OMP_ERROR: + case EXEC_OMP_LOOP: + case EXEC_OMP_MASTER: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_ORDERED: + case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: + case EXEC_OMP_SECTIONS: + case EXEC_OMP_SIMD: + case EXEC_OMP_SINGLE: + case EXEC_OMP_TARGET: + case EXEC_OMP_TARGET_DATA: + case EXEC_OMP_TARGET_ENTER_DATA: + case EXEC_OMP_TARGET_EXIT_DATA: + case EXEC_OMP_TARGET_PARALLEL: + case EXEC_OMP_TARGET_PARALLEL_DO: + case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_PARALLEL_LOOP: + case EXEC_OMP_TARGET_SIMD: + case EXEC_OMP_TARGET_TEAMS: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_TARGET_TEAMS_LOOP: + case EXEC_OMP_TARGET_UPDATE: + case EXEC_OMP_TASK: + case EXEC_OMP_TASKGROUP: + case EXEC_OMP_TASKLOOP: + case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_TASKWAIT: + case EXEC_OMP_TASKYIELD: + case EXEC_OMP_TEAMS: + case EXEC_OMP_TEAMS_DISTRIBUTE: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_TEAMS_LOOP: + case EXEC_OMP_WORKSHARE: + gfc_resolve_omp_directive (code, ns); + break; + + case EXEC_OMP_PARALLEL: + case EXEC_OMP_PARALLEL_DO: + case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_PARALLEL_SECTIONS: + case EXEC_OMP_PARALLEL_WORKSHARE: + omp_workshare_save = omp_workshare_flag; + omp_workshare_flag = 0; + gfc_resolve_omp_directive (code, ns); + omp_workshare_flag = omp_workshare_save; + break; + + default: + gfc_internal_error ("gfc_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) +{ + bool t; + + if (sym->value == NULL) + return; + + if (sym->attr.ext_attr & (1 << EXT_ATTR_DEPRECATED) && sym->attr.referenced) + gfc_warning (OPT_Wdeprecated_declarations, + "Using parameter %qs declared at %L is deprecated", + sym->name, &sym->declared_at); + + if (sym->value->expr_type == EXPR_STRUCTURE) + t= resolve_structure_cons (sym->value, 1); + else + t = gfc_resolve_expr (sym->value); + + if (!t) + return; + + gfc_check_assign_symbol (sym, NULL, sym->value); +} + + +/* Verify any BIND(C) derived types in the namespace so we can report errors + for them once, rather than for each variable declared of that type. */ + +static void +resolve_bind_c_derived_types (gfc_symbol *derived_sym) +{ + if (derived_sym != NULL && derived_sym->attr.flavor == FL_DERIVED + && derived_sym->attr.is_bind_c == 1) + verify_bind_c_derived_type (derived_sym); + + return; +} + + +/* Check the interfaces of DTIO procedures associated with derived + type 'sym'. These procedures can either have typebound bindings or + can appear in DTIO generic interfaces. */ + +static void +gfc_verify_DTIO_procedures (gfc_symbol *sym) +{ + if (!sym || sym->attr.flavor != FL_DERIVED) + return; + + gfc_check_dtio_interfaces (sym); + + return; +} + +/* Verify that any binding labels used in a given namespace do not collide + with the names or binding labels of any global symbols. Multiple INTERFACE + for the same procedure are permitted. */ + +static void +gfc_verify_binding_labels (gfc_symbol *sym) +{ + gfc_gsymbol *gsym; + const char *module; + + if (!sym || !sym->attr.is_bind_c || sym->attr.is_iso_c + || sym->attr.flavor == FL_DERIVED || !sym->binding_label) + return; + + gsym = gfc_find_case_gsymbol (gfc_gsym_root, sym->binding_label); + + if (sym->module) + module = sym->module; + else if (sym->ns && sym->ns->proc_name + && sym->ns->proc_name->attr.flavor == FL_MODULE) + module = sym->ns->proc_name->name; + else if (sym->ns && sym->ns->parent + && sym->ns && sym->ns->parent->proc_name + && sym->ns->parent->proc_name->attr.flavor == FL_MODULE) + module = sym->ns->parent->proc_name->name; + else + module = NULL; + + if (!gsym + || (!gsym->defined + && (gsym->type == GSYM_FUNCTION || gsym->type == GSYM_SUBROUTINE))) + { + if (!gsym) + gsym = gfc_get_gsymbol (sym->binding_label, true); + gsym->where = sym->declared_at; + gsym->sym_name = sym->name; + gsym->binding_label = sym->binding_label; + gsym->ns = sym->ns; + gsym->mod_name = module; + if (sym->attr.function) + gsym->type = GSYM_FUNCTION; + else if (sym->attr.subroutine) + gsym->type = GSYM_SUBROUTINE; + /* Mark as variable/procedure as defined, unless its an INTERFACE. */ + gsym->defined = sym->attr.if_source != IFSRC_IFBODY; + return; + } + + if (sym->attr.flavor == FL_VARIABLE && gsym->type != GSYM_UNKNOWN) + { + gfc_error ("Variable %qs with binding label %qs at %L uses the same global " + "identifier as entity at %L", sym->name, + sym->binding_label, &sym->declared_at, &gsym->where); + /* Clear the binding label to prevent checking multiple times. */ + sym->binding_label = NULL; + return; + } + + if (sym->attr.flavor == FL_VARIABLE && module + && (strcmp (module, gsym->mod_name) != 0 + || strcmp (sym->name, gsym->sym_name) != 0)) + { + /* This can only happen if the variable is defined in a module - if it + isn't the same module, reject it. */ + gfc_error ("Variable %qs from module %qs with binding label %qs at %L " + "uses the same global identifier as entity at %L from module %qs", + sym->name, module, sym->binding_label, + &sym->declared_at, &gsym->where, gsym->mod_name); + sym->binding_label = NULL; + return; + } + + if ((sym->attr.function || sym->attr.subroutine) + && ((gsym->type != GSYM_SUBROUTINE && gsym->type != GSYM_FUNCTION) + || (gsym->defined && sym->attr.if_source != IFSRC_IFBODY)) + && (sym != gsym->ns->proc_name && sym->attr.entry == 0) + && (module != gsym->mod_name + || strcmp (gsym->sym_name, sym->name) != 0 + || (module && strcmp (module, gsym->mod_name) != 0))) + { + /* Print an error if the procedure is defined multiple times; we have to + exclude references to the same procedure via module association or + multiple checks for the same procedure. */ + gfc_error ("Procedure %qs with binding label %qs at %L uses the same " + "global identifier as entity at %L", sym->name, + sym->binding_label, &sym->declared_at, &gsym->where); + sym->binding_label = NULL; + } +} + + +/* Resolve an index expression. */ + +static bool +resolve_index_expr (gfc_expr *e) +{ + if (!gfc_resolve_expr (e)) + return false; + + if (!gfc_simplify_expr (e, 0)) + return false; + + if (!gfc_specification_expr (e)) + return false; + + return true; +} + + +/* Resolve a charlen structure. */ + +static bool +resolve_charlen (gfc_charlen *cl) +{ + int k; + bool saved_specification_expr; + + if (cl->resolved) + return true; + + cl->resolved = 1; + saved_specification_expr = specification_expr; + specification_expr = true; + + if (cl->length_from_typespec) + { + if (!gfc_resolve_expr (cl->length)) + { + specification_expr = saved_specification_expr; + return false; + } + + if (!gfc_simplify_expr (cl->length, 0)) + { + specification_expr = saved_specification_expr; + return false; + } + + /* cl->length has been resolved. It should have an integer type. */ + if (cl->length + && (cl->length->ts.type != BT_INTEGER || cl->length->rank != 0)) + { + gfc_error ("Scalar INTEGER expression expected at %L", + &cl->length->where); + return false; + } + } + else + { + if (!resolve_index_expr (cl->length)) + { + specification_expr = saved_specification_expr; + return false; + } + } + + /* F2008, 4.4.3.2: If the character length parameter value evaluates to + a negative value, the length of character entities declared is zero. */ + if (cl->length && cl->length->expr_type == EXPR_CONSTANT + && mpz_sgn (cl->length->value.integer) < 0) + gfc_replace_expr (cl->length, + gfc_get_int_expr (gfc_charlen_int_kind, NULL, 0)); + + /* Check that the character length is not too large. */ + k = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind, false); + if (cl->length && cl->length->expr_type == EXPR_CONSTANT + && cl->length->ts.type == BT_INTEGER + && mpz_cmp (cl->length->value.integer, gfc_integer_kinds[k].huge) > 0) + { + gfc_error ("String length at %L is too large", &cl->length->where); + specification_expr = saved_specification_expr; + return false; + } + + specification_expr = saved_specification_expr; + return true; +} + + +/* Test for non-constant shape arrays. */ + +static bool +is_non_constant_shape_array (gfc_symbol *sym) +{ + gfc_expr *e; + int i; + bool not_constant; + + not_constant = false; + if (sym->as != NULL) + { + /* Unfortunately, !gfc_is_compile_time_shape hits a legal case that + has not been simplified; parameter array references. Do the + simplification now. */ + for (i = 0; i < sym->as->rank + sym->as->corank; i++) + { + if (i == GFC_MAX_DIMENSIONS) + break; + + e = sym->as->lower[i]; + if (e && (!resolve_index_expr(e) + || !gfc_is_constant_expr (e))) + not_constant = true; + e = sym->as->upper[i]; + if (e && (!resolve_index_expr(e) + || !gfc_is_constant_expr (e))) + not_constant = true; + } + } + return not_constant; +} + +/* Given a symbol and an initialization expression, add code to initialize + the symbol to the function entry. */ +static void +build_init_assign (gfc_symbol *sym, gfc_expr *init) +{ + gfc_expr *lval; + gfc_code *init_st; + gfc_namespace *ns = sym->ns; + + /* Search for the function namespace if this is a contained + function without an explicit result. */ + if (sym->attr.function && sym == sym->result + && sym->name != sym->ns->proc_name->name) + { + ns = ns->contained; + for (;ns; ns = ns->sibling) + if (strcmp (ns->proc_name->name, sym->name) == 0) + break; + } + + if (ns == NULL) + { + gfc_free_expr (init); + return; + } + + /* Build an l-value expression for the result. */ + lval = gfc_lval_expr_from_sym (sym); + + /* Add the code at scope entry. */ + init_st = gfc_get_code (EXEC_INIT_ASSIGN); + init_st->next = ns->code; + ns->code = init_st; + + /* Assign the default initializer to the l-value. */ + init_st->loc = sym->declared_at; + init_st->expr1 = lval; + init_st->expr2 = init; +} + + +/* Whether or not we can generate a default initializer for a symbol. */ + +static bool +can_generate_init (gfc_symbol *sym) +{ + symbol_attribute *a; + if (!sym) + return false; + a = &sym->attr; + + /* These symbols should never have a default initialization. */ + return !( + a->allocatable + || a->external + || a->pointer + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && (CLASS_DATA (sym)->attr.class_pointer + || CLASS_DATA (sym)->attr.proc_pointer)) + || a->in_equivalence + || a->in_common + || a->data + || sym->module + || a->cray_pointee + || a->cray_pointer + || sym->assoc + || (!a->referenced && !a->result) + || (a->dummy && (a->intent != INTENT_OUT + || sym->ns->proc_name->attr.if_source == IFSRC_IFBODY)) + || (a->function && sym != sym->result) + ); +} + + +/* Assign the default initializer to a derived type variable or result. */ + +static void +apply_default_init (gfc_symbol *sym) +{ + gfc_expr *init = NULL; + + if (sym->attr.flavor != FL_VARIABLE && !sym->attr.function) + return; + + if (sym->ts.type == BT_DERIVED && sym->ts.u.derived) + init = gfc_generate_initializer (&sym->ts, can_generate_init (sym)); + + if (init == NULL && sym->ts.type != BT_CLASS) + return; + + build_init_assign (sym, init); + sym->attr.referenced = 1; +} + + +/* Build an initializer for a local. Returns null if the symbol should not have + a default initialization. */ + +static gfc_expr * +build_default_init_expr (gfc_symbol *sym) +{ + /* These symbols should never have a default initialization. */ + if (sym->attr.allocatable + || sym->attr.external + || sym->attr.dummy + || sym->attr.pointer + || sym->attr.in_equivalence + || sym->attr.in_common + || sym->attr.data + || sym->module + || sym->attr.cray_pointee + || sym->attr.cray_pointer + || sym->assoc) + return NULL; + + /* Get the appropriate init expression. */ + return gfc_build_default_init_expr (&sym->ts, &sym->declared_at); +} + +/* Add an initialization expression to a local variable. */ +static void +apply_default_init_local (gfc_symbol *sym) +{ + gfc_expr *init = NULL; + + /* The symbol should be a variable or a function return value. */ + if ((sym->attr.flavor != FL_VARIABLE && !sym->attr.function) + || (sym->attr.function && sym->result != sym)) + return; + + /* Try to build the initializer expression. If we can't initialize + this symbol, then init will be NULL. */ + init = build_default_init_expr (sym); + if (init == NULL) + return; + + /* For saved variables, we don't want to add an initializer at function + entry, so we just add a static initializer. Note that automatic variables + are stack allocated even with -fno-automatic; we have also to exclude + result variable, which are also nonstatic. */ + if (!sym->attr.automatic + && (sym->attr.save || sym->ns->save_all + || (flag_max_stack_var_size == 0 && !sym->attr.result + && (sym->ns->proc_name && !sym->ns->proc_name->attr.recursive) + && (!sym->attr.dimension || !is_non_constant_shape_array (sym))))) + { + /* Don't clobber an existing initializer! */ + gcc_assert (sym->value == NULL); + sym->value = init; + return; + } + + build_init_assign (sym, init); +} + + +/* Resolution of common features of flavors variable and procedure. */ + +static bool +resolve_fl_var_and_proc (gfc_symbol *sym, int mp_flag) +{ + gfc_array_spec *as; + + if (sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym)) + as = CLASS_DATA (sym)->as; + else + as = sym->as; + + /* Constraints on deferred shape variable. */ + if (as == NULL || as->type != AS_DEFERRED) + { + bool pointer, allocatable, dimension; + + if (sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym)) + { + pointer = CLASS_DATA (sym)->attr.class_pointer; + allocatable = CLASS_DATA (sym)->attr.allocatable; + dimension = CLASS_DATA (sym)->attr.dimension; + } + else + { + pointer = sym->attr.pointer && !sym->attr.select_type_temporary; + allocatable = sym->attr.allocatable; + dimension = sym->attr.dimension; + } + + if (allocatable) + { + if (dimension && as->type != AS_ASSUMED_RANK) + { + gfc_error ("Allocatable array %qs at %L must have a deferred " + "shape or assumed rank", sym->name, &sym->declared_at); + return false; + } + else if (!gfc_notify_std (GFC_STD_F2003, "Scalar object " + "%qs at %L may not be ALLOCATABLE", + sym->name, &sym->declared_at)) + return false; + } + + if (pointer && dimension && as->type != AS_ASSUMED_RANK) + { + gfc_error ("Array pointer %qs at %L must have a deferred shape or " + "assumed rank", sym->name, &sym->declared_at); + sym->error = 1; + return false; + } + } + else + { + if (!mp_flag && !sym->attr.allocatable && !sym->attr.pointer + && sym->ts.type != BT_CLASS && !sym->assoc) + { + gfc_error ("Array %qs at %L cannot have a deferred shape", + sym->name, &sym->declared_at); + return false; + } + } + + /* Constraints on polymorphic variables. */ + if (sym->ts.type == BT_CLASS && !(sym->result && sym->result != sym)) + { + /* F03:C502. */ + if (sym->attr.class_ok + && sym->ts.u.derived + && !sym->attr.select_type_temporary + && !UNLIMITED_POLY (sym) + && !gfc_type_is_extensible (CLASS_DATA (sym)->ts.u.derived)) + { + gfc_error ("Type %qs of CLASS variable %qs at %L is not extensible", + CLASS_DATA (sym)->ts.u.derived->name, sym->name, + &sym->declared_at); + return false; + } + + /* F03:C509. */ + /* Assume that use associated symbols were checked in the module ns. + Class-variables that are associate-names are also something special + and excepted from the test. */ + if (!sym->attr.class_ok && !sym->attr.use_assoc && !sym->assoc) + { + gfc_error ("CLASS variable %qs at %L must be dummy, allocatable " + "or pointer", sym->name, &sym->declared_at); + return false; + } + } + + return true; +} + + +/* Additional checks for symbols with flavor variable and derived + type. To be called from resolve_fl_variable. */ + +static bool +resolve_fl_variable_derived (gfc_symbol *sym, int no_init_flag) +{ + gcc_assert (sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS); + + /* Check to see if a derived type is blocked from being host + associated by the presence of another class I symbol in the same + namespace. 14.6.1.3 of the standard and the discussion on + comp.lang.fortran. */ + if (sym->ts.u.derived + && sym->ns != sym->ts.u.derived->ns + && !sym->ts.u.derived->attr.use_assoc + && sym->ns->proc_name->attr.if_source != IFSRC_IFBODY) + { + gfc_symbol *s; + gfc_find_symbol (sym->ts.u.derived->name, sym->ns, 0, &s); + if (s && s->attr.generic) + s = gfc_find_dt_in_generic (s); + if (s && !gfc_fl_struct (s->attr.flavor)) + { + gfc_error ("The type %qs cannot be host associated at %L " + "because it is blocked by an incompatible object " + "of the same name declared at %L", + sym->ts.u.derived->name, &sym->declared_at, + &s->declared_at); + return false; + } + } + + /* 4th constraint in section 11.3: "If an object of a type for which + component-initialization is specified (R429) appears in the + specification-part of a module and does not have the ALLOCATABLE + or POINTER attribute, the object shall have the SAVE attribute." + + The check for initializers is performed with + gfc_has_default_initializer because gfc_default_initializer generates + a hidden default for allocatable components. */ + if (!(sym->value || no_init_flag) && sym->ns->proc_name + && sym->ns->proc_name->attr.flavor == FL_MODULE + && !(sym->ns->save_all && !sym->attr.automatic) && !sym->attr.save + && !sym->attr.pointer && !sym->attr.allocatable + && gfc_has_default_initializer (sym->ts.u.derived) + && !gfc_notify_std (GFC_STD_F2008, "Implied SAVE for module variable " + "%qs at %L, needed due to the default " + "initialization", sym->name, &sym->declared_at)) + return false; + + /* Assign default initializer. */ + if (!(sym->value || sym->attr.pointer || sym->attr.allocatable) + && (!no_init_flag + || (sym->attr.intent == INTENT_OUT + && sym->ns->proc_name->attr.if_source != IFSRC_IFBODY))) + sym->value = gfc_generate_initializer (&sym->ts, can_generate_init (sym)); + + return true; +} + + +/* F2008, C402 (R401): A colon shall not be used as a type-param-value + except in the declaration of an entity or component that has the POINTER + or ALLOCATABLE attribute. */ + +static bool +deferred_requirements (gfc_symbol *sym) +{ + if (sym->ts.deferred + && !(sym->attr.pointer + || sym->attr.allocatable + || sym->attr.associate_var + || sym->attr.omp_udr_artificial_var)) + { + /* If a function has a result variable, only check the variable. */ + if (sym->result && sym->name != sym->result->name) + return true; + + gfc_error ("Entity %qs at %L has a deferred type parameter and " + "requires either the POINTER or ALLOCATABLE attribute", + sym->name, &sym->declared_at); + return false; + } + return true; +} + + +/* Resolve symbols with flavor variable. */ + +static bool +resolve_fl_variable (gfc_symbol *sym, int mp_flag) +{ + const char *auto_save_msg = "Automatic object %qs at %L cannot have the " + "SAVE attribute"; + + if (!resolve_fl_var_and_proc (sym, mp_flag)) + return false; + + /* Set this flag to check that variables are parameters of all entries. + This check is effected by the call to gfc_resolve_expr through + is_non_constant_shape_array. */ + bool saved_specification_expr = specification_expr; + specification_expr = true; + + if (sym->ns->proc_name + && (sym->ns->proc_name->attr.flavor == FL_MODULE + || sym->ns->proc_name->attr.is_main_program) + && !sym->attr.use_assoc + && !sym->attr.allocatable + && !sym->attr.pointer + && is_non_constant_shape_array (sym)) + { + /* F08:C541. The shape of an array defined in a main program or module + * needs to be constant. */ + gfc_error ("The module or main program array %qs at %L must " + "have constant shape", sym->name, &sym->declared_at); + specification_expr = saved_specification_expr; + return false; + } + + /* Constraints on deferred type parameter. */ + if (!deferred_requirements (sym)) + return false; + + if (sym->ts.type == BT_CHARACTER && !sym->attr.associate_var) + { + /* Make sure that character string variables with assumed length are + dummy arguments. */ + gfc_expr *e = NULL; + + if (sym->ts.u.cl) + e = sym->ts.u.cl->length; + else + return false; + + if (e == NULL && !sym->attr.dummy && !sym->attr.result + && !sym->ts.deferred && !sym->attr.select_type_temporary + && !sym->attr.omp_udr_artificial_var) + { + gfc_error ("Entity with assumed character length at %L must be a " + "dummy argument or a PARAMETER", &sym->declared_at); + specification_expr = saved_specification_expr; + return false; + } + + if (e && sym->attr.save == SAVE_EXPLICIT && !gfc_is_constant_expr (e)) + { + gfc_error (auto_save_msg, sym->name, &sym->declared_at); + specification_expr = saved_specification_expr; + return false; + } + + if (!gfc_is_constant_expr (e) + && !(e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.flavor == FL_PARAMETER)) + { + if (!sym->attr.use_assoc && sym->ns->proc_name + && (sym->ns->proc_name->attr.flavor == FL_MODULE + || sym->ns->proc_name->attr.is_main_program)) + { + gfc_error ("%qs at %L must have constant character length " + "in this context", sym->name, &sym->declared_at); + specification_expr = saved_specification_expr; + return false; + } + if (sym->attr.in_common) + { + gfc_error ("COMMON variable %qs at %L must have constant " + "character length", sym->name, &sym->declared_at); + specification_expr = saved_specification_expr; + return false; + } + } + } + + if (sym->value == NULL && sym->attr.referenced) + apply_default_init_local (sym); /* Try to apply a default initialization. */ + + /* Determine if the symbol may not have an initializer. */ + int no_init_flag = 0, automatic_flag = 0; + if (sym->attr.allocatable || sym->attr.external || sym->attr.dummy + || sym->attr.intrinsic || sym->attr.result) + no_init_flag = 1; + else if ((sym->attr.dimension || sym->attr.codimension) && !sym->attr.pointer + && is_non_constant_shape_array (sym)) + { + no_init_flag = automatic_flag = 1; + + /* Also, they must not have the SAVE attribute. + SAVE_IMPLICIT is checked below. */ + if (sym->as && sym->attr.codimension) + { + int corank = sym->as->corank; + sym->as->corank = 0; + no_init_flag = automatic_flag = is_non_constant_shape_array (sym); + sym->as->corank = corank; + } + if (automatic_flag && sym->attr.save == SAVE_EXPLICIT) + { + gfc_error (auto_save_msg, sym->name, &sym->declared_at); + specification_expr = saved_specification_expr; + return false; + } + } + + /* Ensure that any initializer is simplified. */ + if (sym->value) + gfc_simplify_expr (sym->value, 1); + + /* Reject illegal initializers. */ + if (!sym->mark && sym->value) + { + if (sym->attr.allocatable || (sym->ts.type == BT_CLASS + && CLASS_DATA (sym)->attr.allocatable)) + gfc_error ("Allocatable %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + else if (sym->attr.external) + gfc_error ("External %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + else if (sym->attr.dummy) + gfc_error ("Dummy %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + else if (sym->attr.intrinsic) + gfc_error ("Intrinsic %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + else if (sym->attr.result) + gfc_error ("Function result %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + else if (automatic_flag) + gfc_error ("Automatic array %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + else + goto no_init_error; + specification_expr = saved_specification_expr; + return false; + } + +no_init_error: + if (sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS) + { + bool res = resolve_fl_variable_derived (sym, no_init_flag); + specification_expr = saved_specification_expr; + return res; + } + + specification_expr = saved_specification_expr; + return true; +} + + +/* Compare the dummy characteristics of a module procedure interface + declaration with the corresponding declaration in a submodule. */ +static gfc_formal_arglist *new_formal; +static char errmsg[200]; + +static void +compare_fsyms (gfc_symbol *sym) +{ + gfc_symbol *fsym; + + if (sym == NULL || new_formal == NULL) + return; + + fsym = new_formal->sym; + + if (sym == fsym) + return; + + if (strcmp (sym->name, fsym->name) == 0) + { + if (!gfc_check_dummy_characteristics (fsym, sym, true, errmsg, 200)) + gfc_error ("%s at %L", errmsg, &fsym->declared_at); + } +} + + +/* Resolve a procedure. */ + +static bool +resolve_fl_procedure (gfc_symbol *sym, int mp_flag) +{ + gfc_formal_arglist *arg; + bool allocatable_or_pointer = false; + + if (sym->attr.function + && !resolve_fl_var_and_proc (sym, mp_flag)) + return false; + + /* Constraints on deferred type parameter. */ + if (!deferred_requirements (sym)) + return false; + + if (sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.u.cl; + + if (cl && cl->length && gfc_is_constant_expr (cl->length) + && !resolve_charlen (cl)) + return false; + + if ((!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + && sym->attr.proc == PROC_ST_FUNCTION) + { + gfc_error ("Character-valued statement function %qs at %L must " + "have constant length", sym->name, &sym->declared_at); + return false; + } + } + + /* Ensure that derived type for are not of a private type. Internal + module procedures are excluded by 2.2.3.3 - i.e., they are not + externally accessible and can access all the objects accessible in + the host. */ + if (!(sym->ns->parent && sym->ns->parent->proc_name + && sym->ns->parent->proc_name->attr.flavor == FL_MODULE) + && gfc_check_symbol_access (sym)) + { + gfc_interface *iface; + + for (arg = gfc_sym_get_dummy_args (sym); arg; arg = arg->next) + { + if (arg->sym + && arg->sym->ts.type == BT_DERIVED + && arg->sym->ts.u.derived + && !arg->sym->ts.u.derived->attr.use_assoc + && !gfc_check_symbol_access (arg->sym->ts.u.derived) + && !gfc_notify_std (GFC_STD_F2003, "%qs is of a PRIVATE type " + "and cannot be a dummy argument" + " of %qs, which is PUBLIC at %L", + arg->sym->name, sym->name, + &sym->declared_at)) + { + /* Stop this message from recurring. */ + arg->sym->ts.u.derived->attr.access = ACCESS_PUBLIC; + return false; + } + } + + /* PUBLIC interfaces may expose PRIVATE procedures that take types + PRIVATE to the containing module. */ + for (iface = sym->generic; iface; iface = iface->next) + { + for (arg = gfc_sym_get_dummy_args (iface->sym); arg; arg = arg->next) + { + if (arg->sym + && arg->sym->ts.type == BT_DERIVED + && !arg->sym->ts.u.derived->attr.use_assoc + && !gfc_check_symbol_access (arg->sym->ts.u.derived) + && !gfc_notify_std (GFC_STD_F2003, "Procedure %qs in " + "PUBLIC interface %qs at %L " + "takes dummy arguments of %qs which " + "is PRIVATE", iface->sym->name, + sym->name, &iface->sym->declared_at, + gfc_typename(&arg->sym->ts))) + { + /* Stop this message from recurring. */ + arg->sym->ts.u.derived->attr.access = ACCESS_PUBLIC; + return false; + } + } + } + } + + if (sym->attr.function && sym->value && sym->attr.proc != PROC_ST_FUNCTION + && !sym->attr.proc_pointer) + { + gfc_error ("Function %qs at %L cannot have an initializer", + sym->name, &sym->declared_at); + + /* Make sure no second error is issued for this. */ + sym->value->error = 1; + return false; + } + + /* An external symbol may not have an initializer because it is taken to be + a procedure. Exception: Procedure Pointers. */ + if (sym->attr.external && sym->value && !sym->attr.proc_pointer) + { + gfc_error ("External object %qs at %L may not have an initializer", + sym->name, &sym->declared_at); + return false; + } + + /* An elemental function is required to return a scalar 12.7.1 */ + if (sym->attr.elemental && sym->attr.function + && (sym->as || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && CLASS_DATA (sym)->as))) + { + gfc_error ("ELEMENTAL function %qs at %L must have a scalar " + "result", sym->name, &sym->declared_at); + /* Reset so that the error only occurs once. */ + sym->attr.elemental = 0; + return false; + } + + if (sym->attr.proc == PROC_ST_FUNCTION + && (sym->attr.allocatable || sym->attr.pointer)) + { + gfc_error ("Statement function %qs at %L may not have pointer or " + "allocatable attribute", sym->name, &sym->declared_at); + return false; + } + + /* 5.1.1.5 of the Standard: A function name declared with an asterisk + char-len-param shall not be array-valued, pointer-valued, recursive + or pure. ....snip... A character value of * may only be used in the + following ways: (i) Dummy arg of procedure - dummy associates with + actual length; (ii) To declare a named constant; or (iii) External + function - but length must be declared in calling scoping unit. */ + if (sym->attr.function + && sym->ts.type == BT_CHARACTER && !sym->ts.deferred + && sym->ts.u.cl && sym->ts.u.cl->length == NULL) + { + if ((sym->as && sym->as->rank) || (sym->attr.pointer) + || (sym->attr.recursive) || (sym->attr.pure)) + { + if (sym->as && sym->as->rank) + gfc_error ("CHARACTER(*) function %qs at %L cannot be " + "array-valued", sym->name, &sym->declared_at); + + if (sym->attr.pointer) + gfc_error ("CHARACTER(*) function %qs at %L cannot be " + "pointer-valued", sym->name, &sym->declared_at); + + if (sym->attr.pure) + gfc_error ("CHARACTER(*) function %qs at %L cannot be " + "pure", sym->name, &sym->declared_at); + + if (sym->attr.recursive) + gfc_error ("CHARACTER(*) function %qs at %L cannot be " + "recursive", sym->name, &sym->declared_at); + + return false; + } + + /* Appendix B.2 of the standard. Contained functions give an + error anyway. Deferred character length is an F2003 feature. + Don't warn on intrinsic conversion functions, which start + with two underscores. */ + if (!sym->attr.contained && !sym->ts.deferred + && (sym->name[0] != '_' || sym->name[1] != '_')) + gfc_notify_std (GFC_STD_F95_OBS, + "CHARACTER(*) function %qs at %L", + sym->name, &sym->declared_at); + } + + /* F2008, C1218. */ + if (sym->attr.elemental) + { + if (sym->attr.proc_pointer) + { + const char* name = (sym->attr.result ? sym->ns->proc_name->name + : sym->name); + gfc_error ("Procedure pointer %qs at %L shall not be elemental", + name, &sym->declared_at); + return false; + } + if (sym->attr.dummy) + { + gfc_error ("Dummy procedure %qs at %L shall not be elemental", + sym->name, &sym->declared_at); + return false; + } + } + + /* F2018, C15100: "The result of an elemental function shall be scalar, + and shall not have the POINTER or ALLOCATABLE attribute." The scalar + pointer is tested and caught elsewhere. */ + if (sym->result) + allocatable_or_pointer = sym->result->ts.type == BT_CLASS + && CLASS_DATA (sym->result) ? + (CLASS_DATA (sym->result)->attr.allocatable + || CLASS_DATA (sym->result)->attr.pointer) : + (sym->result->attr.allocatable + || sym->result->attr.pointer); + + if (sym->attr.elemental && sym->result + && allocatable_or_pointer) + { + gfc_error ("Function result variable %qs at %L of elemental " + "function %qs shall not have an ALLOCATABLE or POINTER " + "attribute", sym->result->name, + &sym->result->declared_at, sym->name); + return false; + } + + if (sym->attr.is_bind_c && sym->attr.is_c_interop != 1) + { + gfc_formal_arglist *curr_arg; + int has_non_interop_arg = 0; + + if (!verify_bind_c_sym (sym, &(sym->ts), sym->attr.in_common, + sym->common_block)) + { + /* Clear these to prevent looking at them again if there was an + error. */ + sym->attr.is_bind_c = 0; + sym->attr.is_c_interop = 0; + sym->ts.is_c_interop = 0; + } + else + { + /* So far, no errors have been found. */ + sym->attr.is_c_interop = 1; + sym->ts.is_c_interop = 1; + } + + curr_arg = gfc_sym_get_dummy_args (sym); + while (curr_arg != NULL) + { + /* Skip implicitly typed dummy args here. */ + if (curr_arg->sym && curr_arg->sym->attr.implicit_type == 0) + if (!gfc_verify_c_interop_param (curr_arg->sym)) + /* If something is found to fail, record the fact so we + can mark the symbol for the procedure as not being + BIND(C) to try and prevent multiple errors being + reported. */ + has_non_interop_arg = 1; + + curr_arg = curr_arg->next; + } + + /* See if any of the arguments were not interoperable and if so, clear + the procedure symbol to prevent duplicate error messages. */ + if (has_non_interop_arg != 0) + { + sym->attr.is_c_interop = 0; + sym->ts.is_c_interop = 0; + sym->attr.is_bind_c = 0; + } + } + + if (!sym->attr.proc_pointer) + { + if (sym->attr.save == SAVE_EXPLICIT) + { + gfc_error ("PROCEDURE attribute conflicts with SAVE attribute " + "in %qs at %L", sym->name, &sym->declared_at); + return false; + } + if (sym->attr.intent) + { + gfc_error ("PROCEDURE attribute conflicts with INTENT attribute " + "in %qs at %L", sym->name, &sym->declared_at); + return false; + } + if (sym->attr.subroutine && sym->attr.result) + { + gfc_error ("PROCEDURE attribute conflicts with RESULT attribute " + "in %qs at %L", sym->ns->proc_name->name, &sym->declared_at); + return false; + } + if (sym->attr.external && sym->attr.function && !sym->attr.module_procedure + && ((sym->attr.if_source == IFSRC_DECL && !sym->attr.procedure) + || sym->attr.contained)) + { + gfc_error ("EXTERNAL attribute conflicts with FUNCTION attribute " + "in %qs at %L", sym->name, &sym->declared_at); + return false; + } + if (strcmp ("ppr@", sym->name) == 0) + { + gfc_error ("Procedure pointer result %qs at %L " + "is missing the pointer attribute", + sym->ns->proc_name->name, &sym->declared_at); + return false; + } + } + + /* Assume that a procedure whose body is not known has references + to external arrays. */ + if (sym->attr.if_source != IFSRC_DECL) + sym->attr.array_outer_dependency = 1; + + /* Compare the characteristics of a module procedure with the + interface declaration. Ideally this would be done with + gfc_compare_interfaces but, at present, the formal interface + cannot be copied to the ts.interface. */ + if (sym->attr.module_procedure + && sym->attr.if_source == IFSRC_DECL) + { + gfc_symbol *iface; + char name[2*GFC_MAX_SYMBOL_LEN + 1]; + char *module_name; + char *submodule_name; + strcpy (name, sym->ns->proc_name->name); + module_name = strtok (name, "."); + submodule_name = strtok (NULL, "."); + + iface = sym->tlink; + sym->tlink = NULL; + + /* Make sure that the result uses the correct charlen for deferred + length results. */ + if (iface && sym->result + && iface->ts.type == BT_CHARACTER + && iface->ts.deferred) + sym->result->ts.u.cl = iface->ts.u.cl; + + if (iface == NULL) + goto check_formal; + + /* Check the procedure characteristics. */ + if (sym->attr.elemental != iface->attr.elemental) + { + gfc_error ("Mismatch in ELEMENTAL attribute between MODULE " + "PROCEDURE at %L and its interface in %s", + &sym->declared_at, module_name); + return false; + } + + if (sym->attr.pure != iface->attr.pure) + { + gfc_error ("Mismatch in PURE attribute between MODULE " + "PROCEDURE at %L and its interface in %s", + &sym->declared_at, module_name); + return false; + } + + if (sym->attr.recursive != iface->attr.recursive) + { + gfc_error ("Mismatch in RECURSIVE attribute between MODULE " + "PROCEDURE at %L and its interface in %s", + &sym->declared_at, module_name); + return false; + } + + /* Check the result characteristics. */ + if (!gfc_check_result_characteristics (sym, iface, errmsg, 200)) + { + gfc_error ("%s between the MODULE PROCEDURE declaration " + "in MODULE %qs and the declaration at %L in " + "(SUB)MODULE %qs", + errmsg, module_name, &sym->declared_at, + submodule_name ? submodule_name : module_name); + return false; + } + +check_formal: + /* Check the characteristics of the formal arguments. */ + if (sym->formal && sym->formal_ns) + { + for (arg = sym->formal; arg && arg->sym; arg = arg->next) + { + new_formal = arg; + gfc_traverse_ns (sym->formal_ns, compare_fsyms); + } + } + } + return true; +} + + +/* Resolve a list of finalizer procedures. That is, after they have hopefully + been defined and we now know their defined arguments, check that they fulfill + the requirements of the standard for procedures used as finalizers. */ + +static bool +gfc_resolve_finalizers (gfc_symbol* derived, bool *finalizable) +{ + gfc_finalizer* list; + gfc_finalizer** prev_link; /* For removing wrong entries from the list. */ + bool result = true; + bool seen_scalar = false; + gfc_symbol *vtab; + gfc_component *c; + gfc_symbol *parent = gfc_get_derived_super_type (derived); + + if (parent) + gfc_resolve_finalizers (parent, finalizable); + + /* Ensure that derived-type components have a their finalizers resolved. */ + bool has_final = derived->f2k_derived && derived->f2k_derived->finalizers; + for (c = derived->components; c; c = c->next) + if (c->ts.type == BT_DERIVED + && !c->attr.pointer && !c->attr.proc_pointer && !c->attr.allocatable) + { + bool has_final2 = false; + if (!gfc_resolve_finalizers (c->ts.u.derived, &has_final2)) + return false; /* Error. */ + has_final = has_final || has_final2; + } + /* Return early if not finalizable. */ + if (!has_final) + { + if (finalizable) + *finalizable = false; + return true; + } + + /* Walk over the list of finalizer-procedures, check them, and if any one + does not fit in with the standard's definition, print an error and remove + it from the list. */ + prev_link = &derived->f2k_derived->finalizers; + for (list = derived->f2k_derived->finalizers; list; list = *prev_link) + { + gfc_formal_arglist *dummy_args; + gfc_symbol* arg; + gfc_finalizer* i; + int my_rank; + + /* Skip this finalizer if we already resolved it. */ + if (list->proc_tree) + { + if (list->proc_tree->n.sym->formal->sym->as == NULL + || list->proc_tree->n.sym->formal->sym->as->rank == 0) + seen_scalar = true; + prev_link = &(list->next); + continue; + } + + /* Check this exists and is a SUBROUTINE. */ + if (!list->proc_sym->attr.subroutine) + { + gfc_error ("FINAL procedure %qs at %L is not a SUBROUTINE", + list->proc_sym->name, &list->where); + goto error; + } + + /* We should have exactly one argument. */ + dummy_args = gfc_sym_get_dummy_args (list->proc_sym); + if (!dummy_args || dummy_args->next) + { + gfc_error ("FINAL procedure at %L must have exactly one argument", + &list->where); + goto error; + } + arg = dummy_args->sym; + + /* This argument must be of our type. */ + if (arg->ts.type != BT_DERIVED || arg->ts.u.derived != derived) + { + gfc_error ("Argument of FINAL procedure at %L must be of type %qs", + &arg->declared_at, derived->name); + goto error; + } + + /* It must neither be a pointer nor allocatable nor optional. */ + if (arg->attr.pointer) + { + gfc_error ("Argument of FINAL procedure at %L must not be a POINTER", + &arg->declared_at); + goto error; + } + if (arg->attr.allocatable) + { + gfc_error ("Argument of FINAL procedure at %L must not be" + " ALLOCATABLE", &arg->declared_at); + goto error; + } + if (arg->attr.optional) + { + gfc_error ("Argument of FINAL procedure at %L must not be OPTIONAL", + &arg->declared_at); + goto error; + } + + /* It must not be INTENT(OUT). */ + if (arg->attr.intent == INTENT_OUT) + { + gfc_error ("Argument of FINAL procedure at %L must not be" + " INTENT(OUT)", &arg->declared_at); + goto error; + } + + /* Warn if the procedure is non-scalar and not assumed shape. */ + if (warn_surprising && arg->as && arg->as->rank != 0 + && arg->as->type != AS_ASSUMED_SHAPE) + gfc_warning (OPT_Wsurprising, + "Non-scalar FINAL procedure at %L should have assumed" + " shape argument", &arg->declared_at); + + /* Check that it does not match in kind and rank with a FINAL procedure + defined earlier. To really loop over the *earlier* declarations, + we need to walk the tail of the list as new ones were pushed at the + front. */ + /* TODO: Handle kind parameters once they are implemented. */ + my_rank = (arg->as ? arg->as->rank : 0); + for (i = list->next; i; i = i->next) + { + gfc_formal_arglist *dummy_args; + + /* Argument list might be empty; that is an error signalled earlier, + but we nevertheless continued resolving. */ + dummy_args = gfc_sym_get_dummy_args (i->proc_sym); + if (dummy_args) + { + gfc_symbol* i_arg = dummy_args->sym; + const int i_rank = (i_arg->as ? i_arg->as->rank : 0); + if (i_rank == my_rank) + { + gfc_error ("FINAL procedure %qs declared at %L has the same" + " rank (%d) as %qs", + list->proc_sym->name, &list->where, my_rank, + i->proc_sym->name); + goto error; + } + } + } + + /* Is this the/a scalar finalizer procedure? */ + if (my_rank == 0) + seen_scalar = true; + + /* Find the symtree for this procedure. */ + gcc_assert (!list->proc_tree); + list->proc_tree = gfc_find_sym_in_symtree (list->proc_sym); + + prev_link = &list->next; + continue; + + /* Remove wrong nodes immediately from the list so we don't risk any + troubles in the future when they might fail later expectations. */ +error: + i = list; + *prev_link = list->next; + gfc_free_finalizer (i); + result = false; + } + + if (result == false) + return false; + + /* Warn if we haven't seen a scalar finalizer procedure (but we know there + were nodes in the list, must have been for arrays. It is surely a good + idea to have a scalar version there if there's something to finalize. */ + if (warn_surprising && derived->f2k_derived->finalizers && !seen_scalar) + gfc_warning (OPT_Wsurprising, + "Only array FINAL procedures declared for derived type %qs" + " defined at %L, suggest also scalar one", + derived->name, &derived->declared_at); + + vtab = gfc_find_derived_vtab (derived); + c = vtab->ts.u.derived->components->next->next->next->next->next; + gfc_set_sym_referenced (c->initializer->symtree->n.sym); + + if (finalizable) + *finalizable = true; + + return true; +} + + +/* Check if two GENERIC targets are ambiguous and emit an error is they are. */ + +static bool +check_generic_tbp_ambiguity (gfc_tbp_generic* t1, gfc_tbp_generic* t2, + const char* generic_name, locus where) +{ + gfc_symbol *sym1, *sym2; + const char *pass1, *pass2; + gfc_formal_arglist *dummy_args; + + gcc_assert (t1->specific && t2->specific); + gcc_assert (!t1->specific->is_generic); + gcc_assert (!t2->specific->is_generic); + gcc_assert (t1->is_operator == t2->is_operator); + + sym1 = t1->specific->u.specific->n.sym; + sym2 = t2->specific->u.specific->n.sym; + + if (sym1 == sym2) + return true; + + /* Both must be SUBROUTINEs or both must be FUNCTIONs. */ + if (sym1->attr.subroutine != sym2->attr.subroutine + || sym1->attr.function != sym2->attr.function) + { + gfc_error ("%qs and %qs cannot be mixed FUNCTION/SUBROUTINE for" + " GENERIC %qs at %L", + sym1->name, sym2->name, generic_name, &where); + return false; + } + + /* Determine PASS arguments. */ + if (t1->specific->nopass) + pass1 = NULL; + else if (t1->specific->pass_arg) + pass1 = t1->specific->pass_arg; + else + { + dummy_args = gfc_sym_get_dummy_args (t1->specific->u.specific->n.sym); + if (dummy_args) + pass1 = dummy_args->sym->name; + else + pass1 = NULL; + } + if (t2->specific->nopass) + pass2 = NULL; + else if (t2->specific->pass_arg) + pass2 = t2->specific->pass_arg; + else + { + dummy_args = gfc_sym_get_dummy_args (t2->specific->u.specific->n.sym); + if (dummy_args) + pass2 = dummy_args->sym->name; + else + pass2 = NULL; + } + + /* Compare the interfaces. */ + if (gfc_compare_interfaces (sym1, sym2, sym2->name, !t1->is_operator, 0, + NULL, 0, pass1, pass2)) + { + gfc_error ("%qs and %qs for GENERIC %qs at %L are ambiguous", + sym1->name, sym2->name, generic_name, &where); + return false; + } + + return true; +} + + +/* Worker function for resolving a generic procedure binding; this is used to + resolve GENERIC as well as user and intrinsic OPERATOR typebound procedures. + + The difference between those cases is finding possible inherited bindings + that are overridden, as one has to look for them in tb_sym_root, + tb_uop_root or tb_op, respectively. Thus the caller must already find + the super-type and set p->overridden correctly. */ + +static bool +resolve_tb_generic_targets (gfc_symbol* super_type, + gfc_typebound_proc* p, const char* name) +{ + gfc_tbp_generic* target; + gfc_symtree* first_target; + gfc_symtree* inherited; + + gcc_assert (p && p->is_generic); + + /* Try to find the specific bindings for the symtrees in our target-list. */ + gcc_assert (p->u.generic); + for (target = p->u.generic; target; target = target->next) + if (!target->specific) + { + gfc_typebound_proc* overridden_tbp; + gfc_tbp_generic* g; + const char* target_name; + + target_name = target->specific_st->name; + + /* Defined for this type directly. */ + if (target->specific_st->n.tb && !target->specific_st->n.tb->error) + { + target->specific = target->specific_st->n.tb; + goto specific_found; + } + + /* Look for an inherited specific binding. */ + if (super_type) + { + inherited = gfc_find_typebound_proc (super_type, NULL, target_name, + true, NULL); + + if (inherited) + { + gcc_assert (inherited->n.tb); + target->specific = inherited->n.tb; + goto specific_found; + } + } + + gfc_error ("Undefined specific binding %qs as target of GENERIC %qs" + " at %L", target_name, name, &p->where); + return false; + + /* Once we've found the specific binding, check it is not ambiguous with + other specifics already found or inherited for the same GENERIC. */ +specific_found: + gcc_assert (target->specific); + + /* This must really be a specific binding! */ + if (target->specific->is_generic) + { + gfc_error ("GENERIC %qs at %L must target a specific binding," + " %qs is GENERIC, too", name, &p->where, target_name); + return false; + } + + /* Check those already resolved on this type directly. */ + for (g = p->u.generic; g; g = g->next) + if (g != target && g->specific + && !check_generic_tbp_ambiguity (target, g, name, p->where)) + return false; + + /* Check for ambiguity with inherited specific targets. */ + for (overridden_tbp = p->overridden; overridden_tbp; + overridden_tbp = overridden_tbp->overridden) + if (overridden_tbp->is_generic) + { + for (g = overridden_tbp->u.generic; g; g = g->next) + { + gcc_assert (g->specific); + if (!check_generic_tbp_ambiguity (target, g, name, p->where)) + return false; + } + } + } + + /* If we attempt to "overwrite" a specific binding, this is an error. */ + if (p->overridden && !p->overridden->is_generic) + { + gfc_error ("GENERIC %qs at %L cannot overwrite specific binding with" + " the same name", name, &p->where); + return false; + } + + /* Take the SUBROUTINE/FUNCTION attributes of the first specific target, as + all must have the same attributes here. */ + first_target = p->u.generic->specific->u.specific; + gcc_assert (first_target); + p->subroutine = first_target->n.sym->attr.subroutine; + p->function = first_target->n.sym->attr.function; + + return true; +} + + +/* Resolve a GENERIC procedure binding for a derived type. */ + +static bool +resolve_typebound_generic (gfc_symbol* derived, gfc_symtree* st) +{ + gfc_symbol* super_type; + + /* Find the overridden binding if any. */ + st->n.tb->overridden = NULL; + super_type = gfc_get_derived_super_type (derived); + if (super_type) + { + gfc_symtree* overridden; + overridden = gfc_find_typebound_proc (super_type, NULL, st->name, + true, NULL); + + if (overridden && overridden->n.tb) + st->n.tb->overridden = overridden->n.tb; + } + + /* Resolve using worker function. */ + return resolve_tb_generic_targets (super_type, st->n.tb, st->name); +} + + +/* Retrieve the target-procedure of an operator binding and do some checks in + common for intrinsic and user-defined type-bound operators. */ + +static gfc_symbol* +get_checked_tb_operator_target (gfc_tbp_generic* target, locus where) +{ + gfc_symbol* target_proc; + + gcc_assert (target->specific && !target->specific->is_generic); + target_proc = target->specific->u.specific->n.sym; + gcc_assert (target_proc); + + /* F08:C468. All operator bindings must have a passed-object dummy argument. */ + if (target->specific->nopass) + { + gfc_error ("Type-bound operator at %L cannot be NOPASS", &where); + return NULL; + } + + return target_proc; +} + + +/* Resolve a type-bound intrinsic operator. */ + +static bool +resolve_typebound_intrinsic_op (gfc_symbol* derived, gfc_intrinsic_op op, + gfc_typebound_proc* p) +{ + gfc_symbol* super_type; + gfc_tbp_generic* target; + + /* If there's already an error here, do nothing (but don't fail again). */ + if (p->error) + return true; + + /* Operators should always be GENERIC bindings. */ + gcc_assert (p->is_generic); + + /* Look for an overridden binding. */ + super_type = gfc_get_derived_super_type (derived); + if (super_type && super_type->f2k_derived) + p->overridden = gfc_find_typebound_intrinsic_op (super_type, NULL, + op, true, NULL); + else + p->overridden = NULL; + + /* Resolve general GENERIC properties using worker function. */ + if (!resolve_tb_generic_targets (super_type, p, gfc_op2string(op))) + goto error; + + /* Check the targets to be procedures of correct interface. */ + for (target = p->u.generic; target; target = target->next) + { + gfc_symbol* target_proc; + + target_proc = get_checked_tb_operator_target (target, p->where); + if (!target_proc) + goto error; + + if (!gfc_check_operator_interface (target_proc, op, p->where)) + goto error; + + /* Add target to non-typebound operator list. */ + if (!target->specific->deferred && !derived->attr.use_assoc + && p->access != ACCESS_PRIVATE && derived->ns == gfc_current_ns) + { + gfc_interface *head, *intr; + + /* Preempt 'gfc_check_new_interface' for submodules, where the + mechanism for handling module procedures winds up resolving + operator interfaces twice and would otherwise cause an error. */ + for (intr = derived->ns->op[op]; intr; intr = intr->next) + if (intr->sym == target_proc + && target_proc->attr.used_in_submodule) + return true; + + if (!gfc_check_new_interface (derived->ns->op[op], + target_proc, p->where)) + return false; + head = derived->ns->op[op]; + intr = gfc_get_interface (); + intr->sym = target_proc; + intr->where = p->where; + intr->next = head; + derived->ns->op[op] = intr; + } + } + + return true; + +error: + p->error = 1; + return false; +} + + +/* Resolve a type-bound user operator (tree-walker callback). */ + +static gfc_symbol* resolve_bindings_derived; +static bool resolve_bindings_result; + +static bool check_uop_procedure (gfc_symbol* sym, locus where); + +static void +resolve_typebound_user_op (gfc_symtree* stree) +{ + gfc_symbol* super_type; + gfc_tbp_generic* target; + + gcc_assert (stree && stree->n.tb); + + if (stree->n.tb->error) + return; + + /* Operators should always be GENERIC bindings. */ + gcc_assert (stree->n.tb->is_generic); + + /* Find overridden procedure, if any. */ + super_type = gfc_get_derived_super_type (resolve_bindings_derived); + if (super_type && super_type->f2k_derived) + { + gfc_symtree* overridden; + overridden = gfc_find_typebound_user_op (super_type, NULL, + stree->name, true, NULL); + + if (overridden && overridden->n.tb) + stree->n.tb->overridden = overridden->n.tb; + } + else + stree->n.tb->overridden = NULL; + + /* Resolve basically using worker function. */ + if (!resolve_tb_generic_targets (super_type, stree->n.tb, stree->name)) + goto error; + + /* Check the targets to be functions of correct interface. */ + for (target = stree->n.tb->u.generic; target; target = target->next) + { + gfc_symbol* target_proc; + + target_proc = get_checked_tb_operator_target (target, stree->n.tb->where); + if (!target_proc) + goto error; + + if (!check_uop_procedure (target_proc, stree->n.tb->where)) + goto error; + } + + return; + +error: + resolve_bindings_result = false; + stree->n.tb->error = 1; +} + + +/* Resolve the type-bound procedures for a derived type. */ + +static void +resolve_typebound_procedure (gfc_symtree* stree) +{ + gfc_symbol* proc; + locus where; + gfc_symbol* me_arg; + gfc_symbol* super_type; + gfc_component* comp; + + gcc_assert (stree); + + /* Undefined specific symbol from GENERIC target definition. */ + if (!stree->n.tb) + return; + + if (stree->n.tb->error) + return; + + /* If this is a GENERIC binding, use that routine. */ + if (stree->n.tb->is_generic) + { + if (!resolve_typebound_generic (resolve_bindings_derived, stree)) + goto error; + return; + } + + /* Get the target-procedure to check it. */ + gcc_assert (!stree->n.tb->is_generic); + gcc_assert (stree->n.tb->u.specific); + proc = stree->n.tb->u.specific->n.sym; + where = stree->n.tb->where; + + /* Default access should already be resolved from the parser. */ + gcc_assert (stree->n.tb->access != ACCESS_UNKNOWN); + + if (stree->n.tb->deferred) + { + if (!check_proc_interface (proc, &where)) + goto error; + } + else + { + /* If proc has not been resolved at this point, proc->name may + actually be a USE associated entity. See PR fortran/89647. */ + if (!proc->resolve_symbol_called + && proc->attr.function == 0 && proc->attr.subroutine == 0) + { + gfc_symbol *tmp; + gfc_find_symbol (proc->name, gfc_current_ns->parent, 1, &tmp); + if (tmp && tmp->attr.use_assoc) + { + proc->module = tmp->module; + proc->attr.proc = tmp->attr.proc; + proc->attr.function = tmp->attr.function; + proc->attr.subroutine = tmp->attr.subroutine; + proc->attr.use_assoc = tmp->attr.use_assoc; + proc->ts = tmp->ts; + proc->result = tmp->result; + } + } + + /* Check for F08:C465. */ + if ((!proc->attr.subroutine && !proc->attr.function) + || (proc->attr.proc != PROC_MODULE + && proc->attr.if_source != IFSRC_IFBODY + && !proc->attr.module_procedure) + || proc->attr.abstract) + { + gfc_error ("%qs must be a module procedure or an external " + "procedure with an explicit interface at %L", + proc->name, &where); + goto error; + } + } + + stree->n.tb->subroutine = proc->attr.subroutine; + stree->n.tb->function = proc->attr.function; + + /* Find the super-type of the current derived type. We could do this once and + store in a global if speed is needed, but as long as not I believe this is + more readable and clearer. */ + super_type = gfc_get_derived_super_type (resolve_bindings_derived); + + /* If PASS, resolve and check arguments if not already resolved / loaded + from a .mod file. */ + if (!stree->n.tb->nopass && stree->n.tb->pass_arg_num == 0) + { + gfc_formal_arglist *dummy_args; + + dummy_args = gfc_sym_get_dummy_args (proc); + if (stree->n.tb->pass_arg) + { + gfc_formal_arglist *i; + + /* If an explicit passing argument name is given, walk the arg-list + and look for it. */ + + me_arg = NULL; + stree->n.tb->pass_arg_num = 1; + for (i = dummy_args; i; i = i->next) + { + if (!strcmp (i->sym->name, stree->n.tb->pass_arg)) + { + me_arg = i->sym; + break; + } + ++stree->n.tb->pass_arg_num; + } + + if (!me_arg) + { + gfc_error ("Procedure %qs with PASS(%s) at %L has no" + " argument %qs", + proc->name, stree->n.tb->pass_arg, &where, + stree->n.tb->pass_arg); + goto error; + } + } + else + { + /* Otherwise, take the first one; there should in fact be at least + one. */ + stree->n.tb->pass_arg_num = 1; + if (!dummy_args) + { + gfc_error ("Procedure %qs with PASS at %L must have at" + " least one argument", proc->name, &where); + goto error; + } + me_arg = dummy_args->sym; + } + + /* Now check that the argument-type matches and the passed-object + dummy argument is generally fine. */ + + gcc_assert (me_arg); + + if (me_arg->ts.type != BT_CLASS) + { + gfc_error ("Non-polymorphic passed-object dummy argument of %qs" + " at %L", proc->name, &where); + goto error; + } + + if (CLASS_DATA (me_arg)->ts.u.derived + != resolve_bindings_derived) + { + gfc_error ("Argument %qs of %qs with PASS(%s) at %L must be of" + " the derived-type %qs", me_arg->name, proc->name, + me_arg->name, &where, resolve_bindings_derived->name); + goto error; + } + + gcc_assert (me_arg->ts.type == BT_CLASS); + if (CLASS_DATA (me_arg)->as && CLASS_DATA (me_arg)->as->rank != 0) + { + gfc_error ("Passed-object dummy argument of %qs at %L must be" + " scalar", proc->name, &where); + goto error; + } + if (CLASS_DATA (me_arg)->attr.allocatable) + { + gfc_error ("Passed-object dummy argument of %qs at %L must not" + " be ALLOCATABLE", proc->name, &where); + goto error; + } + if (CLASS_DATA (me_arg)->attr.class_pointer) + { + gfc_error ("Passed-object dummy argument of %qs at %L must not" + " be POINTER", proc->name, &where); + goto error; + } + } + + /* If we are extending some type, check that we don't override a procedure + flagged NON_OVERRIDABLE. */ + stree->n.tb->overridden = NULL; + if (super_type) + { + gfc_symtree* overridden; + overridden = gfc_find_typebound_proc (super_type, NULL, + stree->name, true, NULL); + + if (overridden) + { + if (overridden->n.tb) + stree->n.tb->overridden = overridden->n.tb; + + if (!gfc_check_typebound_override (stree, overridden)) + goto error; + } + } + + /* See if there's a name collision with a component directly in this type. */ + for (comp = resolve_bindings_derived->components; comp; comp = comp->next) + if (!strcmp (comp->name, stree->name)) + { + gfc_error ("Procedure %qs at %L has the same name as a component of" + " %qs", + stree->name, &where, resolve_bindings_derived->name); + goto error; + } + + /* Try to find a name collision with an inherited component. */ + if (super_type && gfc_find_component (super_type, stree->name, true, true, + NULL)) + { + gfc_error ("Procedure %qs at %L has the same name as an inherited" + " component of %qs", + stree->name, &where, resolve_bindings_derived->name); + goto error; + } + + stree->n.tb->error = 0; + return; + +error: + resolve_bindings_result = false; + stree->n.tb->error = 1; +} + + +static bool +resolve_typebound_procedures (gfc_symbol* derived) +{ + int op; + gfc_symbol* super_type; + + if (!derived->f2k_derived || !derived->f2k_derived->tb_sym_root) + return true; + + super_type = gfc_get_derived_super_type (derived); + if (super_type) + resolve_symbol (super_type); + + resolve_bindings_derived = derived; + resolve_bindings_result = true; + + if (derived->f2k_derived->tb_sym_root) + gfc_traverse_symtree (derived->f2k_derived->tb_sym_root, + &resolve_typebound_procedure); + + if (derived->f2k_derived->tb_uop_root) + gfc_traverse_symtree (derived->f2k_derived->tb_uop_root, + &resolve_typebound_user_op); + + for (op = 0; op != GFC_INTRINSIC_OPS; ++op) + { + gfc_typebound_proc* p = derived->f2k_derived->tb_op[op]; + if (p && !resolve_typebound_intrinsic_op (derived, + (gfc_intrinsic_op)op, p)) + resolve_bindings_result = false; + } + + return resolve_bindings_result; +} + + +/* Add a derived type to the dt_list. The dt_list is used in trans-types.c + to give all identical derived types the same backend_decl. */ +static void +add_dt_to_dt_list (gfc_symbol *derived) +{ + if (!derived->dt_next) + { + if (gfc_derived_types) + { + derived->dt_next = gfc_derived_types->dt_next; + gfc_derived_types->dt_next = derived; + } + else + { + derived->dt_next = derived; + } + gfc_derived_types = derived; + } +} + + +/* Ensure that a derived-type is really not abstract, meaning that every + inherited DEFERRED binding is overridden by a non-DEFERRED one. */ + +static bool +ensure_not_abstract_walker (gfc_symbol* sub, gfc_symtree* st) +{ + if (!st) + return true; + + if (!ensure_not_abstract_walker (sub, st->left)) + return false; + if (!ensure_not_abstract_walker (sub, st->right)) + return false; + + if (st->n.tb && st->n.tb->deferred) + { + gfc_symtree* overriding; + overriding = gfc_find_typebound_proc (sub, NULL, st->name, true, NULL); + if (!overriding) + return false; + gcc_assert (overriding->n.tb); + if (overriding->n.tb->deferred) + { + gfc_error ("Derived-type %qs declared at %L must be ABSTRACT because" + " %qs is DEFERRED and not overridden", + sub->name, &sub->declared_at, st->name); + return false; + } + } + + return true; +} + +static bool +ensure_not_abstract (gfc_symbol* sub, gfc_symbol* ancestor) +{ + /* The algorithm used here is to recursively travel up the ancestry of sub + and for each ancestor-type, check all bindings. If any of them is + DEFERRED, look it up starting from sub and see if the found (overriding) + binding is not DEFERRED. + This is not the most efficient way to do this, but it should be ok and is + clearer than something sophisticated. */ + + gcc_assert (ancestor && !sub->attr.abstract); + + if (!ancestor->attr.abstract) + return true; + + /* Walk bindings of this ancestor. */ + if (ancestor->f2k_derived) + { + bool t; + t = ensure_not_abstract_walker (sub, ancestor->f2k_derived->tb_sym_root); + if (!t) + return false; + } + + /* Find next ancestor type and recurse on it. */ + ancestor = gfc_get_derived_super_type (ancestor); + if (ancestor) + return ensure_not_abstract (sub, ancestor); + + return true; +} + + +/* This check for typebound defined assignments is done recursively + since the order in which derived types are resolved is not always in + order of the declarations. */ + +static void +check_defined_assignments (gfc_symbol *derived) +{ + gfc_component *c; + + for (c = derived->components; c; c = c->next) + { + if (!gfc_bt_struct (c->ts.type) + || c->attr.pointer + || c->attr.allocatable + || c->attr.proc_pointer_comp + || c->attr.class_pointer + || c->attr.proc_pointer) + continue; + + if (c->ts.u.derived->attr.defined_assign_comp + || (c->ts.u.derived->f2k_derived + && c->ts.u.derived->f2k_derived->tb_op[INTRINSIC_ASSIGN])) + { + derived->attr.defined_assign_comp = 1; + return; + } + + check_defined_assignments (c->ts.u.derived); + if (c->ts.u.derived->attr.defined_assign_comp) + { + derived->attr.defined_assign_comp = 1; + return; + } + } +} + + +/* Resolve a single component of a derived type or structure. */ + +static bool +resolve_component (gfc_component *c, gfc_symbol *sym) +{ + gfc_symbol *super_type; + symbol_attribute *attr; + + if (c->attr.artificial) + return true; + + /* Do not allow vtype components to be resolved in nameless namespaces + such as block data because the procedure pointers will cause ICEs + and vtables are not needed in these contexts. */ + if (sym->attr.vtype && sym->attr.use_assoc + && sym->ns->proc_name == NULL) + return true; + + /* F2008, C442. */ + if ((!sym->attr.is_class || c != sym->components) + && c->attr.codimension + && (!c->attr.allocatable || (c->as && c->as->type != AS_DEFERRED))) + { + gfc_error ("Coarray component %qs at %L must be allocatable with " + "deferred shape", c->name, &c->loc); + return false; + } + + /* F2008, C443. */ + if (c->attr.codimension && c->ts.type == BT_DERIVED + && c->ts.u.derived->ts.is_iso_c) + { + gfc_error ("Component %qs at %L of TYPE(C_PTR) or TYPE(C_FUNPTR) " + "shall not be a coarray", c->name, &c->loc); + return false; + } + + /* F2008, C444. */ + if (gfc_bt_struct (c->ts.type) && c->ts.u.derived->attr.coarray_comp + && (c->attr.codimension || c->attr.pointer || c->attr.dimension + || c->attr.allocatable)) + { + gfc_error ("Component %qs at %L with coarray component " + "shall be a nonpointer, nonallocatable scalar", + c->name, &c->loc); + return false; + } + + /* F2008, C448. */ + if (c->ts.type == BT_CLASS) + { + if (c->attr.class_ok && CLASS_DATA (c)) + { + attr = &(CLASS_DATA (c)->attr); + + /* Fix up contiguous attribute. */ + if (c->attr.contiguous) + attr->contiguous = 1; + } + else + attr = NULL; + } + else + attr = &c->attr; + + if (attr && attr->contiguous && (!attr->dimension || !attr->pointer)) + { + gfc_error ("Component %qs at %L has the CONTIGUOUS attribute but " + "is not an array pointer", c->name, &c->loc); + return false; + } + + /* F2003, 15.2.1 - length has to be one. */ + if (sym->attr.is_bind_c && c->ts.type == BT_CHARACTER + && (c->ts.u.cl == NULL || c->ts.u.cl->length == NULL + || !gfc_is_constant_expr (c->ts.u.cl->length) + || mpz_cmp_si (c->ts.u.cl->length->value.integer, 1) != 0)) + { + gfc_error ("Component %qs of BIND(C) type at %L must have length one", + c->name, &c->loc); + return false; + } + + if (c->attr.proc_pointer && c->ts.interface) + { + gfc_symbol *ifc = c->ts.interface; + + if (!sym->attr.vtype && !check_proc_interface (ifc, &c->loc)) + { + c->tb->error = 1; + return false; + } + + if (ifc->attr.if_source || ifc->attr.intrinsic) + { + /* Resolve interface and copy attributes. */ + if (ifc->formal && !ifc->formal_ns) + resolve_symbol (ifc); + if (ifc->attr.intrinsic) + gfc_resolve_intrinsic (ifc, &ifc->declared_at); + + if (ifc->result) + { + c->ts = ifc->result->ts; + c->attr.allocatable = ifc->result->attr.allocatable; + c->attr.pointer = ifc->result->attr.pointer; + c->attr.dimension = ifc->result->attr.dimension; + c->as = gfc_copy_array_spec (ifc->result->as); + c->attr.class_ok = ifc->result->attr.class_ok; + } + else + { + c->ts = ifc->ts; + c->attr.allocatable = ifc->attr.allocatable; + c->attr.pointer = ifc->attr.pointer; + c->attr.dimension = ifc->attr.dimension; + c->as = gfc_copy_array_spec (ifc->as); + c->attr.class_ok = ifc->attr.class_ok; + } + c->ts.interface = ifc; + c->attr.function = ifc->attr.function; + c->attr.subroutine = ifc->attr.subroutine; + + c->attr.pure = ifc->attr.pure; + c->attr.elemental = ifc->attr.elemental; + c->attr.recursive = ifc->attr.recursive; + c->attr.always_explicit = ifc->attr.always_explicit; + c->attr.ext_attr |= ifc->attr.ext_attr; + /* Copy char length. */ + if (ifc->ts.type == BT_CHARACTER && ifc->ts.u.cl) + { + gfc_charlen *cl = gfc_new_charlen (sym->ns, ifc->ts.u.cl); + if (cl->length && !cl->resolved + && !gfc_resolve_expr (cl->length)) + { + c->tb->error = 1; + return false; + } + c->ts.u.cl = cl; + } + } + } + else if (c->attr.proc_pointer && c->ts.type == BT_UNKNOWN) + { + /* Since PPCs are not implicitly typed, a PPC without an explicit + interface must be a subroutine. */ + gfc_add_subroutine (&c->attr, c->name, &c->loc); + } + + /* Procedure pointer components: Check PASS arg. */ + if (c->attr.proc_pointer && !c->tb->nopass && c->tb->pass_arg_num == 0 + && !sym->attr.vtype) + { + gfc_symbol* me_arg; + + if (c->tb->pass_arg) + { + gfc_formal_arglist* i; + + /* If an explicit passing argument name is given, walk the arg-list + and look for it. */ + + me_arg = NULL; + c->tb->pass_arg_num = 1; + for (i = c->ts.interface->formal; i; i = i->next) + { + if (!strcmp (i->sym->name, c->tb->pass_arg)) + { + me_arg = i->sym; + break; + } + c->tb->pass_arg_num++; + } + + if (!me_arg) + { + gfc_error ("Procedure pointer component %qs with PASS(%s) " + "at %L has no argument %qs", c->name, + c->tb->pass_arg, &c->loc, c->tb->pass_arg); + c->tb->error = 1; + return false; + } + } + else + { + /* Otherwise, take the first one; there should in fact be at least + one. */ + c->tb->pass_arg_num = 1; + if (!c->ts.interface->formal) + { + gfc_error ("Procedure pointer component %qs with PASS at %L " + "must have at least one argument", + c->name, &c->loc); + c->tb->error = 1; + return false; + } + me_arg = c->ts.interface->formal->sym; + } + + /* Now check that the argument-type matches. */ + gcc_assert (me_arg); + if ((me_arg->ts.type != BT_DERIVED && me_arg->ts.type != BT_CLASS) + || (me_arg->ts.type == BT_DERIVED && me_arg->ts.u.derived != sym) + || (me_arg->ts.type == BT_CLASS + && CLASS_DATA (me_arg)->ts.u.derived != sym)) + { + gfc_error ("Argument %qs of %qs with PASS(%s) at %L must be of" + " the derived type %qs", me_arg->name, c->name, + me_arg->name, &c->loc, sym->name); + c->tb->error = 1; + return false; + } + + /* Check for F03:C453. */ + if (CLASS_DATA (me_arg)->attr.dimension) + { + gfc_error ("Argument %qs of %qs with PASS(%s) at %L " + "must be scalar", me_arg->name, c->name, me_arg->name, + &c->loc); + c->tb->error = 1; + return false; + } + + if (CLASS_DATA (me_arg)->attr.class_pointer) + { + gfc_error ("Argument %qs of %qs with PASS(%s) at %L " + "may not have the POINTER attribute", me_arg->name, + c->name, me_arg->name, &c->loc); + c->tb->error = 1; + return false; + } + + if (CLASS_DATA (me_arg)->attr.allocatable) + { + gfc_error ("Argument %qs of %qs with PASS(%s) at %L " + "may not be ALLOCATABLE", me_arg->name, c->name, + me_arg->name, &c->loc); + c->tb->error = 1; + return false; + } + + if (gfc_type_is_extensible (sym) && me_arg->ts.type != BT_CLASS) + { + gfc_error ("Non-polymorphic passed-object dummy argument of %qs" + " at %L", c->name, &c->loc); + return false; + } + + } + + /* Check type-spec if this is not the parent-type component. */ + if (((sym->attr.is_class + && (!sym->components->ts.u.derived->attr.extension + || c != sym->components->ts.u.derived->components)) + || (!sym->attr.is_class + && (!sym->attr.extension || c != sym->components))) + && !sym->attr.vtype + && !resolve_typespec_used (&c->ts, &c->loc, c->name)) + return false; + + super_type = gfc_get_derived_super_type (sym); + + /* If this type is an extension, set the accessibility of the parent + component. */ + if (super_type + && ((sym->attr.is_class + && c == sym->components->ts.u.derived->components) + || (!sym->attr.is_class && c == sym->components)) + && strcmp (super_type->name, c->name) == 0) + c->attr.access = super_type->attr.access; + + /* If this type is an extension, see if this component has the same name + as an inherited type-bound procedure. */ + if (super_type && !sym->attr.is_class + && gfc_find_typebound_proc (super_type, NULL, c->name, true, NULL)) + { + gfc_error ("Component %qs of %qs at %L has the same name as an" + " inherited type-bound procedure", + c->name, sym->name, &c->loc); + return false; + } + + if (c->ts.type == BT_CHARACTER && !c->attr.proc_pointer + && !c->ts.deferred) + { + if (c->ts.u.cl->length == NULL + || (!resolve_charlen(c->ts.u.cl)) + || !gfc_is_constant_expr (c->ts.u.cl->length)) + { + gfc_error ("Character length of component %qs needs to " + "be a constant specification expression at %L", + c->name, + c->ts.u.cl->length ? &c->ts.u.cl->length->where : &c->loc); + return false; + } + } + + if (c->ts.type == BT_CHARACTER && c->ts.deferred + && !c->attr.pointer && !c->attr.allocatable) + { + gfc_error ("Character component %qs of %qs at %L with deferred " + "length must be a POINTER or ALLOCATABLE", + c->name, sym->name, &c->loc); + return false; + } + + /* Add the hidden deferred length field. */ + if (c->ts.type == BT_CHARACTER + && (c->ts.deferred || c->attr.pdt_string) + && !c->attr.function + && !sym->attr.is_class) + { + char name[GFC_MAX_SYMBOL_LEN+9]; + gfc_component *strlen; + sprintf (name, "_%s_length", c->name); + strlen = gfc_find_component (sym, name, true, true, NULL); + if (strlen == NULL) + { + if (!gfc_add_component (sym, name, &strlen)) + return false; + strlen->ts.type = BT_INTEGER; + strlen->ts.kind = gfc_charlen_int_kind; + strlen->attr.access = ACCESS_PRIVATE; + strlen->attr.artificial = 1; + } + } + + if (c->ts.type == BT_DERIVED + && sym->component_access != ACCESS_PRIVATE + && gfc_check_symbol_access (sym) + && !is_sym_host_assoc (c->ts.u.derived, sym->ns) + && !c->ts.u.derived->attr.use_assoc + && !gfc_check_symbol_access (c->ts.u.derived) + && !gfc_notify_std (GFC_STD_F2003, "the component %qs is a " + "PRIVATE type and cannot be a component of " + "%qs, which is PUBLIC at %L", c->name, + sym->name, &sym->declared_at)) + return false; + + if ((sym->attr.sequence || sym->attr.is_bind_c) && c->ts.type == BT_CLASS) + { + gfc_error ("Polymorphic component %s at %L in SEQUENCE or BIND(C) " + "type %s", c->name, &c->loc, sym->name); + return false; + } + + if (sym->attr.sequence) + { + if (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.sequence == 0) + { + gfc_error ("Component %s of SEQUENCE type declared at %L does " + "not have the SEQUENCE attribute", + c->ts.u.derived->name, &sym->declared_at); + return false; + } + } + + if (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.generic) + c->ts.u.derived = gfc_find_dt_in_generic (c->ts.u.derived); + else if (c->ts.type == BT_CLASS && c->attr.class_ok + && CLASS_DATA (c)->ts.u.derived->attr.generic) + CLASS_DATA (c)->ts.u.derived + = gfc_find_dt_in_generic (CLASS_DATA (c)->ts.u.derived); + + /* If an allocatable component derived type is of the same type as + the enclosing derived type, we need a vtable generating so that + the __deallocate procedure is created. */ + if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) + && c->ts.u.derived == sym && c->attr.allocatable == 1) + gfc_find_vtab (&c->ts); + + /* Ensure that all the derived type components are put on the + derived type list; even in formal namespaces, where derived type + pointer components might not have been declared. */ + if (c->ts.type == BT_DERIVED + && c->ts.u.derived + && c->ts.u.derived->components + && c->attr.pointer + && sym != c->ts.u.derived) + add_dt_to_dt_list (c->ts.u.derived); + + if (c->as && c->as->type != AS_DEFERRED + && (c->attr.pointer || c->attr.allocatable)) + return false; + + if (!gfc_resolve_array_spec (c->as, + !(c->attr.pointer || c->attr.proc_pointer + || c->attr.allocatable))) + return false; + + if (c->initializer && !sym->attr.vtype + && !c->attr.pdt_kind && !c->attr.pdt_len + && !gfc_check_assign_symbol (sym, c, c->initializer)) + return false; + + return true; +} + + +/* Be nice about the locus for a structure expression - show the locus of the + first non-null sub-expression if we can. */ + +static locus * +cons_where (gfc_expr *struct_expr) +{ + gfc_constructor *cons; + + gcc_assert (struct_expr && struct_expr->expr_type == EXPR_STRUCTURE); + + cons = gfc_constructor_first (struct_expr->value.constructor); + for (; cons; cons = gfc_constructor_next (cons)) + { + if (cons->expr && cons->expr->expr_type != EXPR_NULL) + return &cons->expr->where; + } + + return &struct_expr->where; +} + +/* Resolve the components of a structure type. Much less work than derived + types. */ + +static bool +resolve_fl_struct (gfc_symbol *sym) +{ + gfc_component *c; + gfc_expr *init = NULL; + bool success; + + /* Make sure UNIONs do not have overlapping initializers. */ + if (sym->attr.flavor == FL_UNION) + { + for (c = sym->components; c; c = c->next) + { + if (init && c->initializer) + { + gfc_error ("Conflicting initializers in union at %L and %L", + cons_where (init), cons_where (c->initializer)); + gfc_free_expr (c->initializer); + c->initializer = NULL; + } + if (init == NULL) + init = c->initializer; + } + } + + success = true; + for (c = sym->components; c; c = c->next) + if (!resolve_component (c, sym)) + success = false; + + if (!success) + return false; + + if (sym->components) + add_dt_to_dt_list (sym); + + return true; +} + + +/* Resolve the components of a derived type. This does not have to wait until + resolution stage, but can be done as soon as the dt declaration has been + parsed. */ + +static bool +resolve_fl_derived0 (gfc_symbol *sym) +{ + gfc_symbol* super_type; + gfc_component *c; + gfc_formal_arglist *f; + bool success; + + if (sym->attr.unlimited_polymorphic) + return true; + + super_type = gfc_get_derived_super_type (sym); + + /* F2008, C432. */ + if (super_type && sym->attr.coarray_comp && !super_type->attr.coarray_comp) + { + gfc_error ("As extending type %qs at %L has a coarray component, " + "parent type %qs shall also have one", sym->name, + &sym->declared_at, super_type->name); + return false; + } + + /* Ensure the extended type gets resolved before we do. */ + if (super_type && !resolve_fl_derived0 (super_type)) + return false; + + /* An ABSTRACT type must be extensible. */ + if (sym->attr.abstract && !gfc_type_is_extensible (sym)) + { + gfc_error ("Non-extensible derived-type %qs at %L must not be ABSTRACT", + sym->name, &sym->declared_at); + return false; + } + + c = (sym->attr.is_class) ? sym->components->ts.u.derived->components + : sym->components; + + success = true; + for ( ; c != NULL; c = c->next) + if (!resolve_component (c, sym)) + success = false; + + if (!success) + return false; + + /* Now add the caf token field, where needed. */ + if (flag_coarray != GFC_FCOARRAY_NONE + && !sym->attr.is_class && !sym->attr.vtype) + { + for (c = sym->components; c; c = c->next) + if (!c->attr.dimension && !c->attr.codimension + && (c->attr.allocatable || c->attr.pointer)) + { + char name[GFC_MAX_SYMBOL_LEN+9]; + gfc_component *token; + sprintf (name, "_caf_%s", c->name); + token = gfc_find_component (sym, name, true, true, NULL); + if (token == NULL) + { + if (!gfc_add_component (sym, name, &token)) + return false; + token->ts.type = BT_VOID; + token->ts.kind = gfc_default_integer_kind; + token->attr.access = ACCESS_PRIVATE; + token->attr.artificial = 1; + token->attr.caf_token = 1; + } + } + } + + check_defined_assignments (sym); + + if (!sym->attr.defined_assign_comp && super_type) + sym->attr.defined_assign_comp + = super_type->attr.defined_assign_comp; + + /* If this is a non-ABSTRACT type extending an ABSTRACT one, ensure that + all DEFERRED bindings are overridden. */ + if (super_type && super_type->attr.abstract && !sym->attr.abstract + && !sym->attr.is_class + && !ensure_not_abstract (sym, super_type)) + return false; + + /* Check that there is a component for every PDT parameter. */ + if (sym->attr.pdt_template) + { + for (f = sym->formal; f; f = f->next) + { + if (!f->sym) + continue; + c = gfc_find_component (sym, f->sym->name, true, true, NULL); + if (c == NULL) + { + gfc_error ("Parameterized type %qs does not have a component " + "corresponding to parameter %qs at %L", sym->name, + f->sym->name, &sym->declared_at); + break; + } + } + } + + /* Add derived type to the derived type list. */ + add_dt_to_dt_list (sym); + + return true; +} + + +/* The following procedure does the full resolution of a derived type, + including resolution of all type-bound procedures (if present). In contrast + to 'resolve_fl_derived0' this can only be done after the module has been + parsed completely. */ + +static bool +resolve_fl_derived (gfc_symbol *sym) +{ + gfc_symbol *gen_dt = NULL; + + if (sym->attr.unlimited_polymorphic) + return true; + + if (!sym->attr.is_class) + gfc_find_symbol (sym->name, sym->ns, 0, &gen_dt); + if (gen_dt && gen_dt->generic && gen_dt->generic->next + && (!gen_dt->generic->sym->attr.use_assoc + || gen_dt->generic->sym->module != gen_dt->generic->next->sym->module) + && !gfc_notify_std (GFC_STD_F2003, "Generic name %qs of function " + "%qs at %L being the same name as derived " + "type at %L", sym->name, + gen_dt->generic->sym == sym + ? gen_dt->generic->next->sym->name + : gen_dt->generic->sym->name, + gen_dt->generic->sym == sym + ? &gen_dt->generic->next->sym->declared_at + : &gen_dt->generic->sym->declared_at, + &sym->declared_at)) + return false; + + if (sym->components == NULL && !sym->attr.zero_comp && !sym->attr.use_assoc) + { + gfc_error ("Derived type %qs at %L has not been declared", + sym->name, &sym->declared_at); + return false; + } + + /* Resolve the finalizer procedures. */ + if (!gfc_resolve_finalizers (sym, NULL)) + return false; + + if (sym->attr.is_class && sym->ts.u.derived == NULL) + { + /* Fix up incomplete CLASS symbols. */ + gfc_component *data = gfc_find_component (sym, "_data", true, true, NULL); + gfc_component *vptr = gfc_find_component (sym, "_vptr", true, true, NULL); + + /* Nothing more to do for unlimited polymorphic entities. */ + if (data->ts.u.derived->attr.unlimited_polymorphic) + return true; + else if (vptr->ts.u.derived == NULL) + { + gfc_symbol *vtab = gfc_find_derived_vtab (data->ts.u.derived); + gcc_assert (vtab); + vptr->ts.u.derived = vtab->ts.u.derived; + if (!resolve_fl_derived0 (vptr->ts.u.derived)) + return false; + } + } + + if (!resolve_fl_derived0 (sym)) + return false; + + /* Resolve the type-bound procedures. */ + if (!resolve_typebound_procedures (sym)) + return false; + + /* Generate module vtables subject to their accessibility and their not + being vtables or pdt templates. If this is not done class declarations + in external procedures wind up with their own version and so SELECT TYPE + fails because the vptrs do not have the same address. */ + if (gfc_option.allow_std & GFC_STD_F2003 + && sym->ns->proc_name + && sym->ns->proc_name->attr.flavor == FL_MODULE + && sym->attr.access != ACCESS_PRIVATE + && !(sym->attr.use_assoc || sym->attr.vtype || sym->attr.pdt_template)) + { + gfc_symbol *vtab = gfc_find_derived_vtab (sym); + gfc_set_sym_referenced (vtab); + } + + return true; +} + + +static bool +resolve_fl_namelist (gfc_symbol *sym) +{ + gfc_namelist *nl; + gfc_symbol *nlsym; + + for (nl = sym->namelist; nl; nl = nl->next) + { + /* Check again, the check in match only works if NAMELIST comes + after the decl. */ + if (nl->sym->as && nl->sym->as->type == AS_ASSUMED_SIZE) + { + gfc_error ("Assumed size array %qs in namelist %qs at %L is not " + "allowed", nl->sym->name, sym->name, &sym->declared_at); + return false; + } + + if (nl->sym->as && nl->sym->as->type == AS_ASSUMED_SHAPE + && !gfc_notify_std (GFC_STD_F2003, "NAMELIST array object %qs " + "with assumed shape in namelist %qs at %L", + nl->sym->name, sym->name, &sym->declared_at)) + return false; + + if (is_non_constant_shape_array (nl->sym) + && !gfc_notify_std (GFC_STD_F2003, "NAMELIST array object %qs " + "with nonconstant shape in namelist %qs at %L", + nl->sym->name, sym->name, &sym->declared_at)) + return false; + + if (nl->sym->ts.type == BT_CHARACTER + && (nl->sym->ts.u.cl->length == NULL + || !gfc_is_constant_expr (nl->sym->ts.u.cl->length)) + && !gfc_notify_std (GFC_STD_F2003, "NAMELIST object %qs with " + "nonconstant character length in " + "namelist %qs at %L", nl->sym->name, + sym->name, &sym->declared_at)) + return false; + + } + + /* Reject PRIVATE objects in a PUBLIC namelist. */ + if (gfc_check_symbol_access (sym)) + { + for (nl = sym->namelist; nl; nl = nl->next) + { + if (!nl->sym->attr.use_assoc + && !is_sym_host_assoc (nl->sym, sym->ns) + && !gfc_check_symbol_access (nl->sym)) + { + gfc_error ("NAMELIST object %qs was declared PRIVATE and " + "cannot be member of PUBLIC namelist %qs at %L", + nl->sym->name, sym->name, &sym->declared_at); + return false; + } + + if (nl->sym->ts.type == BT_DERIVED + && (nl->sym->ts.u.derived->attr.alloc_comp + || nl->sym->ts.u.derived->attr.pointer_comp)) + { + if (!gfc_notify_std (GFC_STD_F2003, "NAMELIST object %qs in " + "namelist %qs at %L with ALLOCATABLE " + "or POINTER components", nl->sym->name, + sym->name, &sym->declared_at)) + return false; + return true; + } + + /* Types with private components that came here by USE-association. */ + if (nl->sym->ts.type == BT_DERIVED + && derived_inaccessible (nl->sym->ts.u.derived)) + { + gfc_error ("NAMELIST object %qs has use-associated PRIVATE " + "components and cannot be member of namelist %qs at %L", + nl->sym->name, sym->name, &sym->declared_at); + return false; + } + + /* Types with private components that are defined in the same module. */ + if (nl->sym->ts.type == BT_DERIVED + && !is_sym_host_assoc (nl->sym->ts.u.derived, sym->ns) + && nl->sym->ts.u.derived->attr.private_comp) + { + gfc_error ("NAMELIST object %qs has PRIVATE components and " + "cannot be a member of PUBLIC namelist %qs at %L", + nl->sym->name, sym->name, &sym->declared_at); + return false; + } + } + } + + + /* 14.1.2 A module or internal procedure represent local entities + of the same type as a namelist member and so are not allowed. */ + for (nl = sym->namelist; nl; nl = nl->next) + { + if (nl->sym->ts.kind != 0 && nl->sym->attr.flavor == FL_VARIABLE) + continue; + + if (nl->sym->attr.function && nl->sym == nl->sym->result) + if ((nl->sym == sym->ns->proc_name) + || + (sym->ns->parent && nl->sym == sym->ns->parent->proc_name)) + continue; + + nlsym = NULL; + if (nl->sym->name) + gfc_find_symbol (nl->sym->name, sym->ns, 1, &nlsym); + if (nlsym && nlsym->attr.flavor == FL_PROCEDURE) + { + gfc_error ("PROCEDURE attribute conflicts with NAMELIST " + "attribute in %qs at %L", nlsym->name, + &sym->declared_at); + return false; + } + } + + return true; +} + + +static bool +resolve_fl_parameter (gfc_symbol *sym) +{ + /* A parameter array's shape needs to be constant. */ + if (sym->as != NULL + && (sym->as->type == AS_DEFERRED + || is_non_constant_shape_array (sym))) + { + gfc_error ("Parameter array %qs at %L cannot be automatic " + "or of deferred shape", sym->name, &sym->declared_at); + return false; + } + + /* Constraints on deferred type parameter. */ + if (!deferred_requirements (sym)) + return false; + + /* Make sure a parameter that has been implicitly typed still + matches the implicit type, since PARAMETER statements can precede + IMPLICIT statements. */ + if (sym->attr.implicit_type + && !gfc_compare_types (&sym->ts, gfc_get_default_type (sym->name, + sym->ns))) + { + gfc_error ("Implicitly typed PARAMETER %qs at %L doesn't match a " + "later IMPLICIT type", sym->name, &sym->declared_at); + return false; + } + + /* 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->ts.type == BT_DERIVED + && !gfc_compare_types (&sym->ts, &sym->value->ts)) + { + gfc_error ("Incompatible derived type in PARAMETER at %L", + &sym->value->where); + return false; + } + + /* F03:C509,C514. */ + if (sym->ts.type == BT_CLASS) + { + gfc_error ("CLASS variable %qs at %L cannot have the PARAMETER attribute", + sym->name, &sym->declared_at); + return false; + } + + return true; +} + + +/* Called by resolve_symbol to check PDTs. */ + +static void +resolve_pdt (gfc_symbol* sym) +{ + gfc_symbol *derived = NULL; + gfc_actual_arglist *param; + gfc_component *c; + bool const_len_exprs = true; + bool assumed_len_exprs = false; + symbol_attribute *attr; + + if (sym->ts.type == BT_DERIVED) + { + derived = sym->ts.u.derived; + attr = &(sym->attr); + } + else if (sym->ts.type == BT_CLASS) + { + derived = CLASS_DATA (sym)->ts.u.derived; + attr = &(CLASS_DATA (sym)->attr); + } + else + gcc_unreachable (); + + gcc_assert (derived->attr.pdt_type); + + for (param = sym->param_list; param; param = param->next) + { + c = gfc_find_component (derived, param->name, false, true, NULL); + gcc_assert (c); + if (c->attr.pdt_kind) + continue; + + if (param->expr && !gfc_is_constant_expr (param->expr) + && c->attr.pdt_len) + const_len_exprs = false; + else if (param->spec_type == SPEC_ASSUMED) + assumed_len_exprs = true; + + if (param->spec_type == SPEC_DEFERRED + && !attr->allocatable && !attr->pointer) + gfc_error ("The object %qs at %L has a deferred LEN " + "parameter %qs and is neither allocatable " + "nor a pointer", sym->name, &sym->declared_at, + param->name); + + } + + if (!const_len_exprs + && (sym->ns->proc_name->attr.is_main_program + || sym->ns->proc_name->attr.flavor == FL_MODULE + || sym->attr.save != SAVE_NONE)) + gfc_error ("The AUTOMATIC object %qs at %L must not have the " + "SAVE attribute or be a variable declared in the " + "main program, a module or a submodule(F08/C513)", + sym->name, &sym->declared_at); + + if (assumed_len_exprs && !(sym->attr.dummy + || sym->attr.select_type_temporary || sym->attr.associate_var)) + gfc_error ("The object %qs at %L with ASSUMED type parameters " + "must be a dummy or a SELECT TYPE selector(F08/4.2)", + sym->name, &sym->declared_at); +} + + +/* 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) +{ + int check_constant, mp_flag; + gfc_symtree *symtree; + gfc_symtree *this_symtree; + gfc_namespace *ns; + gfc_component *c; + symbol_attribute class_attr; + gfc_array_spec *as; + bool saved_specification_expr; + + if (sym->resolve_symbol_called >= 1) + return; + sym->resolve_symbol_called = 1; + + /* No symbol will ever have union type; only components can be unions. + Union type declaration symbols have type BT_UNKNOWN but flavor FL_UNION + (just like derived type declaration symbols have flavor FL_DERIVED). */ + gcc_assert (sym->ts.type != BT_UNION); + + /* Coarrayed polymorphic objects with allocatable or pointer components are + yet unsupported for -fcoarray=lib. */ + if (flag_coarray == GFC_FCOARRAY_LIB && sym->ts.type == BT_CLASS + && sym->ts.u.derived && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.codimension + && CLASS_DATA (sym)->ts.u.derived + && (CLASS_DATA (sym)->ts.u.derived->attr.alloc_comp + || CLASS_DATA (sym)->ts.u.derived->attr.pointer_comp)) + { + gfc_error ("Sorry, allocatable/pointer components in polymorphic (CLASS) " + "type coarrays at %L are unsupported", &sym->declared_at); + return; + } + + if (sym->attr.artificial) + return; + + if (sym->attr.unlimited_polymorphic) + return; + + if (sym->attr.flavor == FL_UNKNOWN + || (sym->attr.flavor == FL_PROCEDURE && !sym->attr.intrinsic + && !sym->attr.generic && !sym->attr.external + && sym->attr.if_source == IFSRC_UNKNOWN + && sym->ts.type == BT_UNKNOWN)) + { + + /* If we find that a flavorless symbol is an interface in one of the + parent namespaces, find its symtree in this namespace, free the + symbol and set the symtree to point to the interface symbol. */ + for (ns = gfc_current_ns->parent; ns; ns = ns->parent) + { + symtree = gfc_find_symtree (ns->sym_root, sym->name); + if (symtree && (symtree->n.sym->generic || + (symtree->n.sym->attr.flavor == FL_PROCEDURE + && sym->ns->construct_entities))) + { + this_symtree = gfc_find_symtree (gfc_current_ns->sym_root, + sym->name); + if (this_symtree->n.sym == sym) + { + symtree->n.sym->refs++; + gfc_release_symbol (sym); + this_symtree->n.sym = symtree->n.sym; + return; + } + } + } + + /* Otherwise give it a flavor according to such attributes as + it has. */ + if (sym->attr.flavor == FL_UNKNOWN && sym->attr.external == 0 + && sym->attr.intrinsic == 0) + sym->attr.flavor = FL_VARIABLE; + else if (sym->attr.flavor == FL_UNKNOWN) + { + sym->attr.flavor = FL_PROCEDURE; + if (sym->attr.dimension) + sym->attr.function = 1; + } + } + + if (sym->attr.external && sym->ts.type != BT_UNKNOWN && !sym->attr.function) + gfc_add_function (&sym->attr, sym->name, &sym->declared_at); + + if (sym->attr.procedure && sym->attr.if_source != IFSRC_DECL + && !resolve_procedure_interface (sym)) + return; + + if (sym->attr.is_protected && !sym->attr.proc_pointer + && (sym->attr.procedure || sym->attr.external)) + { + if (sym->attr.external) + gfc_error ("PROTECTED attribute conflicts with EXTERNAL attribute " + "at %L", &sym->declared_at); + else + gfc_error ("PROCEDURE attribute conflicts with PROTECTED attribute " + "at %L", &sym->declared_at); + + return; + } + + if (sym->attr.flavor == FL_DERIVED && !resolve_fl_derived (sym)) + return; + + else if ((sym->attr.flavor == FL_STRUCT || sym->attr.flavor == FL_UNION) + && !resolve_fl_struct (sym)) + return; + + /* 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); + + /* Make sure that the intrinsic is consistent with its internal + representation. This needs to be done before assigning a default + type to avoid spurious warnings. */ + if (sym->attr.flavor != FL_MODULE && sym->attr.intrinsic + && !gfc_resolve_intrinsic (sym, &sym->declared_at)) + return; + + /* Resolve associate names. */ + if (sym->assoc) + resolve_assoc_var (sym, true); + + /* 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, 1, NULL); + } + + if (sym->attr.flavor == FL_PROCEDURE && sym->attr.external + && !sym->attr.function && !sym->attr.subroutine + && gfc_get_default_type (sym->name, sym->ns)->type == BT_UNKNOWN) + gfc_add_subroutine (&sym->attr, sym->name, &sym->declared_at); + + if (sym->attr.flavor == FL_PROCEDURE && sym->attr.function) + { + /* The specific case of an external procedure should emit an error + in the case that there is no implicit type. */ + if (!mp_flag) + { + if (!sym->attr.mixed_entry_master) + gfc_set_default_type (sym, sym->attr.external, NULL); + } + else + { + /* Result may be in another namespace. */ + resolve_symbol (sym->result); + + if (!sym->result->attr.proc_pointer) + { + sym->ts = sym->result->ts; + sym->as = gfc_copy_array_spec (sym->result->as); + sym->attr.dimension = sym->result->attr.dimension; + sym->attr.pointer = sym->result->attr.pointer; + sym->attr.allocatable = sym->result->attr.allocatable; + sym->attr.contiguous = sym->result->attr.contiguous; + } + } + } + } + else if (mp_flag && sym->attr.flavor == FL_PROCEDURE && sym->attr.function) + { + bool saved_specification_expr = specification_expr; + bool saved_formal_arg_flag = formal_arg_flag; + + specification_expr = true; + formal_arg_flag = true; + gfc_resolve_array_spec (sym->result->as, false); + formal_arg_flag = saved_formal_arg_flag; + specification_expr = saved_specification_expr; + } + + if (sym->ts.type == BT_CLASS && sym->attr.class_ok && sym->ts.u.derived) + { + as = CLASS_DATA (sym)->as; + class_attr = CLASS_DATA (sym)->attr; + class_attr.pointer = class_attr.class_pointer; + } + else + { + class_attr = sym->attr; + as = sym->as; + } + + /* F2008, C530. */ + if (sym->attr.contiguous + && (!class_attr.dimension + || (as->type != AS_ASSUMED_SHAPE && as->type != AS_ASSUMED_RANK + && !class_attr.pointer))) + { + gfc_error ("%qs at %L has the CONTIGUOUS attribute but is not an " + "array pointer or an assumed-shape or assumed-rank array", + sym->name, &sym->declared_at); + return; + } + + /* Assumed size arrays and assumed shape arrays must be dummy + arguments. Array-spec's of implied-shape should have been resolved to + AS_EXPLICIT already. */ + + if (as) + { + /* If AS_IMPLIED_SHAPE makes it to here, it must be a bad + specification expression. */ + if (as->type == AS_IMPLIED_SHAPE) + { + int i; + for (i=0; i<as->rank; i++) + { + if (as->lower[i] != NULL && as->upper[i] == NULL) + { + gfc_error ("Bad specification for assumed size array at %L", + &as->lower[i]->where); + return; + } + } + gcc_unreachable(); + } + + if (((as->type == AS_ASSUMED_SIZE && !as->cp_was_assumed) + || as->type == AS_ASSUMED_SHAPE) + && !sym->attr.dummy && !sym->attr.select_type_temporary) + { + if (as->type == AS_ASSUMED_SIZE) + gfc_error ("Assumed size array at %L must be a dummy argument", + &sym->declared_at); + else + gfc_error ("Assumed shape array at %L must be a dummy argument", + &sym->declared_at); + return; + } + /* TS 29113, C535a. */ + if (as->type == AS_ASSUMED_RANK && !sym->attr.dummy + && !sym->attr.select_type_temporary + && !(cs_base && cs_base->current + && cs_base->current->op == EXEC_SELECT_RANK)) + { + gfc_error ("Assumed-rank array at %L must be a dummy argument", + &sym->declared_at); + return; + } + if (as->type == AS_ASSUMED_RANK + && (sym->attr.codimension || sym->attr.value)) + { + gfc_error ("Assumed-rank array at %L may not have the VALUE or " + "CODIMENSION attribute", &sym->declared_at); + return; + } + } + + /* 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.value && !sym->attr.dummy) + { + gfc_error ("%qs at %L cannot have the VALUE attribute because " + "it is not a dummy argument", sym->name, &sym->declared_at); + return; + } + + if (sym->attr.value && sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.u.cl; + if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + { + gfc_error ("Character dummy variable %qs at %L with VALUE " + "attribute must have constant length", + sym->name, &sym->declared_at); + return; + } + + if (sym->ts.is_c_interop + && mpz_cmp_si (cl->length->value.integer, 1) != 0) + { + gfc_error ("C interoperable character dummy variable %qs at %L " + "with VALUE attribute must have length one", + sym->name, &sym->declared_at); + return; + } + } + + if (sym->ts.type == BT_DERIVED && !sym->attr.is_iso_c + && sym->ts.u.derived->attr.generic) + { + sym->ts.u.derived = gfc_find_dt_in_generic (sym->ts.u.derived); + if (!sym->ts.u.derived) + { + gfc_error ("The derived type %qs at %L is of type %qs, " + "which has not been defined", sym->name, + &sym->declared_at, sym->ts.u.derived->name); + sym->ts.type = BT_UNKNOWN; + return; + } + } + + /* Use the same constraints as TYPE(*), except for the type check + and that only scalars and assumed-size arrays are permitted. */ + if (sym->attr.ext_attr & (1 << EXT_ATTR_NO_ARG_CHECK)) + { + if (!sym->attr.dummy) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute shall be " + "a dummy argument", sym->name, &sym->declared_at); + return; + } + + if (sym->ts.type != BT_ASSUMED && sym->ts.type != BT_INTEGER + && sym->ts.type != BT_REAL && sym->ts.type != BT_LOGICAL + && sym->ts.type != BT_COMPLEX) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute shall be " + "of type TYPE(*) or of an numeric intrinsic type", + sym->name, &sym->declared_at); + return; + } + + if (sym->attr.allocatable || sym->attr.codimension + || sym->attr.pointer || sym->attr.value) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute may not " + "have the ALLOCATABLE, CODIMENSION, POINTER or VALUE " + "attribute", sym->name, &sym->declared_at); + return; + } + + if (sym->attr.intent == INTENT_OUT) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute may not " + "have the INTENT(OUT) attribute", + sym->name, &sym->declared_at); + return; + } + if (sym->attr.dimension && sym->as->type != AS_ASSUMED_SIZE) + { + gfc_error ("Variable %s at %L with NO_ARG_CHECK attribute shall " + "either be a scalar or an assumed-size array", + sym->name, &sym->declared_at); + return; + } + + /* Set the type to TYPE(*) and add a dimension(*) to ensure + NO_ARG_CHECK is correctly handled in trans*.c, e.g. with + packing. */ + sym->ts.type = BT_ASSUMED; + sym->as = gfc_get_array_spec (); + sym->as->type = AS_ASSUMED_SIZE; + sym->as->rank = 1; + sym->as->lower[0] = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1); + } + else if (sym->ts.type == BT_ASSUMED) + { + /* TS 29113, C407a. */ + if (!sym->attr.dummy) + { + gfc_error ("Assumed type of variable %s at %L is only permitted " + "for dummy variables", sym->name, &sym->declared_at); + return; + } + if (sym->attr.allocatable || sym->attr.codimension + || sym->attr.pointer || sym->attr.value) + { + gfc_error ("Assumed-type variable %s at %L may not have the " + "ALLOCATABLE, CODIMENSION, POINTER or VALUE attribute", + sym->name, &sym->declared_at); + return; + } + if (sym->attr.intent == INTENT_OUT) + { + gfc_error ("Assumed-type variable %s at %L may not have the " + "INTENT(OUT) attribute", + sym->name, &sym->declared_at); + return; + } + if (sym->attr.dimension && sym->as->type == AS_EXPLICIT) + { + gfc_error ("Assumed-type variable %s at %L shall not be an " + "explicit-shape array", sym->name, &sym->declared_at); + return; + } + } + + /* If the symbol is marked as bind(c), that it is declared at module level + scope and verify its type and kind. Do not do the latter for symbols + that are implicitly typed because that is handled in + gfc_set_default_type. Handle dummy arguments and procedure definitions + separately. Also, anything that is use associated is not handled here + but instead is handled in the module it is declared in. Finally, derived + type definitions are allowed to be BIND(C) since that only implies that + they're interoperable, and they are checked fully for interoperability + when a variable is declared of that type. */ + if (sym->attr.is_bind_c && sym->attr.use_assoc == 0 + && sym->attr.dummy == 0 && sym->attr.flavor != FL_PROCEDURE + && sym->attr.flavor != FL_DERIVED) + { + bool t = true; + + /* First, make sure the variable is declared at the + module-level scope (J3/04-007, Section 15.3). */ + if (sym->ns->proc_name->attr.flavor != FL_MODULE && + sym->attr.in_common == 0) + { + gfc_error ("Variable %qs at %L cannot be BIND(C) because it " + "is neither a COMMON block nor declared at the " + "module level scope", sym->name, &(sym->declared_at)); + t = false; + } + else if (sym->ts.type == BT_CHARACTER + && (sym->ts.u.cl == NULL || sym->ts.u.cl->length == NULL + || !gfc_is_constant_expr (sym->ts.u.cl->length) + || mpz_cmp_si (sym->ts.u.cl->length->value.integer, 1) != 0)) + { + gfc_error ("BIND(C) Variable %qs at %L must have length one", + sym->name, &sym->declared_at); + t = false; + } + else if (sym->common_head != NULL && sym->attr.implicit_type == 0) + { + t = verify_com_block_vars_c_interop (sym->common_head); + } + else if (sym->attr.implicit_type == 0) + { + /* If type() declaration, we need to verify that the components + of the given type are all C interoperable, etc. */ + if (sym->ts.type == BT_DERIVED && + sym->ts.u.derived->attr.is_c_interop != 1) + { + /* Make sure the user marked the derived type as BIND(C). If + not, call the verify routine. This could print an error + for the derived type more than once if multiple variables + of that type are declared. */ + if (sym->ts.u.derived->attr.is_bind_c != 1) + verify_bind_c_derived_type (sym->ts.u.derived); + t = false; + } + + /* Verify the variable itself as C interoperable if it + is BIND(C). It is not possible for this to succeed if + the verify_bind_c_derived_type failed, so don't have to handle + any error returned by verify_bind_c_derived_type. */ + t = verify_bind_c_sym (sym, &(sym->ts), sym->attr.in_common, + sym->common_block); + } + + if (!t) + { + /* clear the is_bind_c flag to prevent reporting errors more than + once if something failed. */ + sym->attr.is_bind_c = 0; + return; + } + } + + /* If a derived type symbol has reached this point, without its + type being declared, we have an error. Notice that most + conditions that produce undefined derived types have already + been dealt with. However, the likes of: + implicit type(t) (t) ..... call foo (t) will get us here if + the type is not declared in the scope of the implicit + statement. Change the type to BT_UNKNOWN, both because it is so + and to prevent an ICE. */ + if (sym->ts.type == BT_DERIVED && !sym->attr.is_iso_c + && sym->ts.u.derived->components == NULL + && !sym->ts.u.derived->attr.zero_comp) + { + gfc_error ("The derived type %qs at %L is of type %qs, " + "which has not been defined", sym->name, + &sym->declared_at, sym->ts.u.derived->name); + sym->ts.type = BT_UNKNOWN; + return; + } + + /* Make sure that the derived type has been resolved and that the + derived type is visible in the symbol's namespace, if it is a + module function and is not PRIVATE. */ + if (sym->ts.type == BT_DERIVED + && sym->ts.u.derived->attr.use_assoc + && sym->ns->proc_name + && sym->ns->proc_name->attr.flavor == FL_MODULE + && !resolve_fl_derived (sym->ts.u.derived)) + return; + + /* Unless the derived-type declaration is use associated, Fortran 95 + does not allow public entries of private derived types. + See 4.4.1 (F95) and 4.5.1.1 (F2003); and related interpretation + 161 in 95-006r3. */ + if (sym->ts.type == BT_DERIVED + && sym->ns->proc_name && sym->ns->proc_name->attr.flavor == FL_MODULE + && !sym->ts.u.derived->attr.use_assoc + && gfc_check_symbol_access (sym) + && !gfc_check_symbol_access (sym->ts.u.derived) + && !gfc_notify_std (GFC_STD_F2003, "PUBLIC %s %qs at %L of PRIVATE " + "derived type %qs", + (sym->attr.flavor == FL_PARAMETER) + ? "parameter" : "variable", + sym->name, &sym->declared_at, + sym->ts.u.derived->name)) + return; + + /* F2008, C1302. */ + if (sym->ts.type == BT_DERIVED + && ((sym->ts.u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV + && sym->ts.u.derived->intmod_sym_id == ISOFORTRAN_LOCK_TYPE) + || sym->ts.u.derived->attr.lock_comp) + && !sym->attr.codimension && !sym->ts.u.derived->attr.coarray_comp) + { + gfc_error ("Variable %s at %L of type LOCK_TYPE or with subcomponent of " + "type LOCK_TYPE must be a coarray", sym->name, + &sym->declared_at); + return; + } + + /* TS18508, C702/C703. */ + if (sym->ts.type == BT_DERIVED + && ((sym->ts.u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV + && sym->ts.u.derived->intmod_sym_id == ISOFORTRAN_EVENT_TYPE) + || sym->ts.u.derived->attr.event_comp) + && !sym->attr.codimension && !sym->ts.u.derived->attr.coarray_comp) + { + gfc_error ("Variable %s at %L of type EVENT_TYPE or with subcomponent of " + "type EVENT_TYPE must be a coarray", sym->name, + &sym->declared_at); + return; + } + + /* An assumed-size array with INTENT(OUT) shall not be of a type for which + default initialization is defined (5.1.2.4.4). */ + if (sym->ts.type == BT_DERIVED + && sym->attr.dummy + && sym->attr.intent == INTENT_OUT + && sym->as + && sym->as->type == AS_ASSUMED_SIZE) + { + for (c = sym->ts.u.derived->components; c; c = c->next) + { + if (c->initializer) + { + gfc_error ("The INTENT(OUT) dummy argument %qs at %L is " + "ASSUMED SIZE and so cannot have a default initializer", + sym->name, &sym->declared_at); + return; + } + } + } + + /* F2008, C542. */ + if (sym->ts.type == BT_DERIVED && sym->attr.dummy + && sym->attr.intent == INTENT_OUT && sym->attr.lock_comp) + { + gfc_error ("Dummy argument %qs at %L of LOCK_TYPE shall not be " + "INTENT(OUT)", sym->name, &sym->declared_at); + return; + } + + /* TS18508. */ + if (sym->ts.type == BT_DERIVED && sym->attr.dummy + && sym->attr.intent == INTENT_OUT && sym->attr.event_comp) + { + gfc_error ("Dummy argument %qs at %L of EVENT_TYPE shall not be " + "INTENT(OUT)", sym->name, &sym->declared_at); + return; + } + + /* F2008, C525. */ + if ((((sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.coarray_comp) + || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.coarray_comp)) + || class_attr.codimension) + && (sym->attr.result || sym->result == sym)) + { + gfc_error ("Function result %qs at %L shall not be a coarray or have " + "a coarray component", sym->name, &sym->declared_at); + return; + } + + /* F2008, C524. */ + if (sym->attr.codimension && sym->ts.type == BT_DERIVED + && sym->ts.u.derived->ts.is_iso_c) + { + gfc_error ("Variable %qs at %L of TYPE(C_PTR) or TYPE(C_FUNPTR) " + "shall not be a coarray", sym->name, &sym->declared_at); + return; + } + + /* F2008, C525. */ + if (((sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.coarray_comp) + || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.coarray_comp)) + && (class_attr.codimension || class_attr.pointer || class_attr.dimension + || class_attr.allocatable)) + { + gfc_error ("Variable %qs at %L with coarray component shall be a " + "nonpointer, nonallocatable scalar, which is not a coarray", + sym->name, &sym->declared_at); + return; + } + + /* F2008, C526. The function-result case was handled above. */ + if (class_attr.codimension + && !(class_attr.allocatable || sym->attr.dummy || sym->attr.save + || sym->attr.select_type_temporary + || sym->attr.associate_var + || (sym->ns->save_all && !sym->attr.automatic) + || sym->ns->proc_name->attr.flavor == FL_MODULE + || sym->ns->proc_name->attr.is_main_program + || sym->attr.function || sym->attr.result || sym->attr.use_assoc)) + { + gfc_error ("Variable %qs at %L is a coarray and is not ALLOCATABLE, SAVE " + "nor a dummy argument", sym->name, &sym->declared_at); + return; + } + /* F2008, C528. */ + else if (class_attr.codimension && !sym->attr.select_type_temporary + && !class_attr.allocatable && as && as->cotype == AS_DEFERRED) + { + gfc_error ("Coarray variable %qs at %L shall not have codimensions with " + "deferred shape", sym->name, &sym->declared_at); + return; + } + else if (class_attr.codimension && class_attr.allocatable && as + && (as->cotype != AS_DEFERRED || as->type != AS_DEFERRED)) + { + gfc_error ("Allocatable coarray variable %qs at %L must have " + "deferred shape", sym->name, &sym->declared_at); + return; + } + + /* F2008, C541. */ + if ((((sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.coarray_comp) + || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && sym->ts.u.derived && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.coarray_comp)) + || (class_attr.codimension && class_attr.allocatable)) + && sym->attr.dummy && sym->attr.intent == INTENT_OUT) + { + gfc_error ("Variable %qs at %L is INTENT(OUT) and can thus not be an " + "allocatable coarray or have coarray components", + sym->name, &sym->declared_at); + return; + } + + if (class_attr.codimension && sym->attr.dummy + && sym->ns->proc_name && sym->ns->proc_name->attr.is_bind_c) + { + gfc_error ("Coarray dummy variable %qs at %L not allowed in BIND(C) " + "procedure %qs", sym->name, &sym->declared_at, + sym->ns->proc_name->name); + return; + } + + if (sym->ts.type == BT_LOGICAL + && ((sym->attr.function && sym->attr.is_bind_c && sym->result == sym) + || ((sym->attr.dummy || sym->attr.result) && sym->ns->proc_name + && sym->ns->proc_name->attr.is_bind_c))) + { + int i; + for (i = 0; gfc_logical_kinds[i].kind; i++) + if (gfc_logical_kinds[i].kind == sym->ts.kind) + break; + if (!gfc_logical_kinds[i].c_bool && sym->attr.dummy + && !gfc_notify_std (GFC_STD_GNU, "LOGICAL dummy argument %qs at " + "%L with non-C_Bool kind in BIND(C) procedure " + "%qs", sym->name, &sym->declared_at, + sym->ns->proc_name->name)) + return; + else if (!gfc_logical_kinds[i].c_bool + && !gfc_notify_std (GFC_STD_GNU, "LOGICAL result variable " + "%qs at %L with non-C_Bool kind in " + "BIND(C) procedure %qs", sym->name, + &sym->declared_at, + sym->attr.function ? sym->name + : sym->ns->proc_name->name)) + return; + } + + switch (sym->attr.flavor) + { + case FL_VARIABLE: + if (!resolve_fl_variable (sym, mp_flag)) + return; + break; + + case FL_PROCEDURE: + if (sym->formal && !sym->formal_ns) + { + /* Check that none of the arguments are a namelist. */ + gfc_formal_arglist *formal = sym->formal; + + for (; formal; formal = formal->next) + if (formal->sym && formal->sym->attr.flavor == FL_NAMELIST) + { + gfc_error ("Namelist %qs cannot be an argument to " + "subroutine or function at %L", + formal->sym->name, &sym->declared_at); + return; + } + } + + if (!resolve_fl_procedure (sym, mp_flag)) + return; + break; + + case FL_NAMELIST: + if (!resolve_fl_namelist (sym)) + return; + break; + + case FL_PARAMETER: + if (!resolve_fl_parameter (sym)) + return; + break; + + default: + break; + } + + /* Resolve array specifier. Check as well some constraints + on COMMON blocks. */ + + check_constant = sym->attr.in_common && !sym->attr.pointer; + + /* Set the formal_arg_flag so that check_conflict will not throw + an error for host associated variables in the specification + expression for an array_valued function. */ + if ((sym->attr.function || sym->attr.result) && sym->as) + formal_arg_flag = true; + + saved_specification_expr = specification_expr; + specification_expr = true; + gfc_resolve_array_spec (sym->as, check_constant); + specification_expr = saved_specification_expr; + + formal_arg_flag = false; + + /* Resolve formal namespaces. */ + if (sym->formal_ns && sym->formal_ns != gfc_current_ns + && !sym->attr.contained && !sym->attr.intrinsic) + gfc_resolve (sym->formal_ns); + + /* Make sure the formal namespace is present. */ + if (sym->formal && !sym->formal_ns) + { + gfc_formal_arglist *formal = sym->formal; + while (formal && !formal->sym) + formal = formal->next; + + if (formal) + { + sym->formal_ns = formal->sym->ns; + if (sym->formal_ns && sym->ns != formal->sym->ns) + sym->formal_ns->refs++; + } + } + + /* Check threadprivate restrictions. */ + if (sym->attr.threadprivate + && !(sym->attr.save || sym->attr.data || sym->attr.in_common) + && !(sym->ns->save_all && !sym->attr.automatic) + && sym->module == NULL + && (sym->ns->proc_name == NULL + || (sym->ns->proc_name->attr.flavor != FL_MODULE + && !sym->ns->proc_name->attr.is_main_program))) + gfc_error ("Threadprivate at %L isn't SAVEd", &sym->declared_at); + + /* Check omp declare target restrictions. */ + if (sym->attr.omp_declare_target + && sym->attr.flavor == FL_VARIABLE + && !sym->attr.save + && !(sym->ns->save_all && !sym->attr.automatic) + && (!sym->attr.in_common + && sym->module == NULL + && (sym->ns->proc_name == NULL + || (sym->ns->proc_name->attr.flavor != FL_MODULE + && !sym->ns->proc_name->attr.is_main_program)))) + gfc_error ("!$OMP DECLARE TARGET variable %qs at %L isn't SAVEd", + sym->name, &sym->declared_at); + + /* If we have come this far we can apply default-initializers, as + described in 14.7.5, to those variables that have not already + been assigned one. */ + if (sym->ts.type == BT_DERIVED + && !sym->value + && !sym->attr.allocatable + && !sym->attr.alloc_comp) + { + symbol_attribute *a = &sym->attr; + + if ((!a->save && !a->dummy && !a->pointer + && !a->in_common && !a->use_assoc + && a->referenced + && !((a->function || a->result) + && (!a->dimension + || sym->ts.u.derived->attr.alloc_comp + || sym->ts.u.derived->attr.pointer_comp)) + && !(a->function && sym != sym->result)) + || (a->dummy && !a->pointer && a->intent == INTENT_OUT + && sym->ns->proc_name->attr.if_source != IFSRC_IFBODY)) + apply_default_init (sym); + else if (a->function && sym->result && a->access != ACCESS_PRIVATE + && (sym->ts.u.derived->attr.alloc_comp + || sym->ts.u.derived->attr.pointer_comp)) + /* Mark the result symbol to be referenced, when it has allocatable + components. */ + sym->result->attr.referenced = 1; + } + + if (sym->ts.type == BT_CLASS && sym->ns == gfc_current_ns + && sym->attr.dummy && sym->attr.intent == INTENT_OUT + && sym->ns->proc_name->attr.if_source != IFSRC_IFBODY + && !CLASS_DATA (sym)->attr.class_pointer + && !CLASS_DATA (sym)->attr.allocatable) + apply_default_init (sym); + + /* If this symbol has a type-spec, check it. */ + if (sym->attr.flavor == FL_VARIABLE || sym->attr.flavor == FL_PARAMETER + || (sym->attr.flavor == FL_PROCEDURE && sym->attr.function)) + if (!resolve_typespec_used (&sym->ts, &sym->declared_at, sym->name)) + return; + + if (sym->param_list) + resolve_pdt (sym); +} + + +/************* Resolve DATA statements *************/ + +static struct +{ + gfc_data_value *vnode; + mpz_t left; +} +values; + + +/* Advance the values structure to point to the next value in the data list. */ + +static bool +next_data_value (void) +{ + while (mpz_cmp_ui (values.left, 0) == 0) + { + + if (values.vnode->next == NULL) + return false; + + values.vnode = values.vnode->next; + mpz_set (values.left, values.vnode->repeat); + } + + return true; +} + + +static bool +check_data_variable (gfc_data_variable *var, locus *where) +{ + gfc_expr *e; + mpz_t size; + mpz_t offset; + bool t; + ar_type mark = AR_UNKNOWN; + int i; + mpz_t section_index[GFC_MAX_DIMENSIONS]; + gfc_ref *ref; + gfc_array_ref *ar; + gfc_symbol *sym; + int has_pointer; + + if (!gfc_resolve_expr (var->expr)) + return false; + + ar = NULL; + mpz_init_set_si (offset, 0); + e = var->expr; + + if (e->expr_type == EXPR_FUNCTION && e->value.function.isym + && e->value.function.isym->id == GFC_ISYM_CAF_GET) + e = e->value.function.actual->expr; + + if (e->expr_type != EXPR_VARIABLE) + { + gfc_error ("Expecting definable entity near %L", where); + return false; + } + + sym = e->symtree->n.sym; + + if (sym->ns->is_block_data && !sym->attr.in_common) + { + gfc_error ("BLOCK DATA element %qs at %L must be in COMMON", + sym->name, &sym->declared_at); + return false; + } + + if (e->ref == NULL && sym->as) + { + gfc_error ("DATA array %qs at %L must be specified in a previous" + " declaration", sym->name, where); + return false; + } + + if (gfc_is_coindexed (e)) + { + gfc_error ("DATA element %qs at %L cannot have a coindex", sym->name, + where); + return false; + } + + has_pointer = sym->attr.pointer; + + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type == REF_COMPONENT && ref->u.c.component->attr.pointer) + has_pointer = 1; + + if (has_pointer) + { + if (ref->type == REF_ARRAY && ref->u.ar.type != AR_FULL) + { + gfc_error ("DATA element %qs at %L is a pointer and so must " + "be a full array", sym->name, where); + return false; + } + + if (values.vnode->expr->expr_type == EXPR_CONSTANT) + { + gfc_error ("DATA object near %L has the pointer attribute " + "and the corresponding DATA value is not a valid " + "initial-data-target", where); + return false; + } + } + + if (ref->type == REF_COMPONENT && ref->u.c.component->attr.allocatable) + { + gfc_error ("DATA element %qs at %L cannot have the ALLOCATABLE " + "attribute", ref->u.c.component->name, &e->where); + return false; + } + } + + if (e->rank == 0 || has_pointer) + { + mpz_init_set_ui (size, 1); + ref = NULL; + } + 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; + } + gcc_assert (ref); + + /* Set marks according to the reference pattern. */ + switch (ref->u.ar.type) + { + case AR_FULL: + mark = AR_FULL; + break; + + case AR_SECTION: + ar = &ref->u.ar; + /* Get the start position of array section. */ + gfc_get_section_index (ar, section_index, &offset); + mark = AR_SECTION; + break; + + default: + gcc_unreachable (); + } + + if (!gfc_array_size (e, &size)) + { + gfc_error ("Nonconstant array section at %L in DATA statement", + where); + mpz_clear (offset); + return false; + } + } + + t = true; + + while (mpz_cmp_ui (size, 0) > 0) + { + if (!next_data_value ()) + { + gfc_error ("DATA statement at %L has more variables than values", + where); + t = false; + break; + } + + t = gfc_check_assign (var->expr, values.vnode->expr, 0); + if (!t) + break; + + /* If we have more than one element left in the repeat count, + and we have more than one element left in the target variable, + then create a range assignment. */ + /* FIXME: Only done for full arrays for now, since array sections + seem tricky. */ + if (mark == AR_FULL && ref && ref->next == NULL + && mpz_cmp_ui (values.left, 1) > 0 && mpz_cmp_ui (size, 1) > 0) + { + mpz_t range; + + if (mpz_cmp (size, values.left) >= 0) + { + mpz_init_set (range, values.left); + mpz_sub (size, size, values.left); + mpz_set_ui (values.left, 0); + } + else + { + mpz_init_set (range, size); + mpz_sub (values.left, values.left, size); + mpz_set_ui (size, 0); + } + + t = gfc_assign_data_value (var->expr, values.vnode->expr, + offset, &range); + + mpz_add (offset, offset, range); + mpz_clear (range); + + if (!t) + break; + } + + /* Assign initial value to symbol. */ + else + { + mpz_sub_ui (values.left, values.left, 1); + mpz_sub_ui (size, size, 1); + + t = gfc_assign_data_value (var->expr, values.vnode->expr, + offset, NULL); + if (!t) + break; + + if (mark == AR_FULL) + mpz_add_ui (offset, offset, 1); + + /* Modify the array section indexes and recalculate the offset + for next element. */ + else if (mark == AR_SECTION) + gfc_advance_section (section_index, ar, &offset); + } + } + + if (mark == AR_SECTION) + { + for (i = 0; i < ar->dimen; i++) + mpz_clear (section_index[i]); + } + + mpz_clear (size); + mpz_clear (offset); + + return t; +} + + +static bool traverse_data_var (gfc_data_variable *, locus *); + +/* Iterate over a list of elements in a DATA statement. */ + +static bool +traverse_data_list (gfc_data_variable *var, locus *where) +{ + mpz_t trip; + iterator_stack frame; + gfc_expr *e, *start, *end, *step; + bool retval = true; + + mpz_init (frame.value); + mpz_init (trip); + + start = gfc_copy_expr (var->iter.start); + end = gfc_copy_expr (var->iter.end); + step = gfc_copy_expr (var->iter.step); + + if (!gfc_simplify_expr (start, 1) + || start->expr_type != EXPR_CONSTANT) + { + gfc_error ("start of implied-do loop at %L could not be " + "simplified to a constant value", &start->where); + retval = false; + goto cleanup; + } + if (!gfc_simplify_expr (end, 1) + || end->expr_type != EXPR_CONSTANT) + { + gfc_error ("end of implied-do loop at %L could not be " + "simplified to a constant value", &end->where); + retval = false; + goto cleanup; + } + if (!gfc_simplify_expr (step, 1) + || step->expr_type != EXPR_CONSTANT) + { + gfc_error ("step of implied-do loop at %L could not be " + "simplified to a constant value", &step->where); + retval = false; + goto cleanup; + } + if (mpz_cmp_si (step->value.integer, 0) == 0) + { + gfc_error ("step of implied-do loop at %L shall not be zero", + &step->where); + retval = false; + goto cleanup; + } + + mpz_set (trip, end->value.integer); + mpz_sub (trip, trip, start->value.integer); + mpz_add (trip, trip, step->value.integer); + + mpz_div (trip, trip, step->value.integer); + + mpz_set (frame.value, 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)) + { + retval = false; + goto cleanup; + } + + e = gfc_copy_expr (var->expr); + if (!gfc_simplify_expr (e, 1)) + { + gfc_free_expr (e); + retval = false; + goto cleanup; + } + + mpz_add (frame.value, frame.value, step->value.integer); + + mpz_sub_ui (trip, trip, 1); + } + +cleanup: + mpz_clear (frame.value); + mpz_clear (trip); + + gfc_free_expr (start); + gfc_free_expr (end); + gfc_free_expr (step); + + iter_stack = frame.prev; + return retval; +} + + +/* Type resolve variables in the variable list of a DATA statement. */ + +static bool +traverse_data_var (gfc_data_variable *var, locus *where) +{ + bool 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) + return false; + } + + return true; +} + + +/* 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 bool +resolve_data_variables (gfc_data_variable *d) +{ + for (; d; d = d->next) + { + if (d->list == NULL) + { + if (!gfc_resolve_expr (d->expr)) + return false; + } + else + { + if (!gfc_resolve_iterator (&d->iter, false, true)) + return false; + + if (!resolve_data_variables (d->list)) + return false; + } + } + + return true; +} + + +/* 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)) + return; + + values.vnode = d->value; + if (d->value == NULL) + mpz_set_ui (values.left, 0); + else + mpz_set (values.left, d->value->repeat); + + if (!traverse_data_var (d->var, &d->where)) + return; + + /* At this point, we better not have any values left. */ + + if (next_data_value ()) + gfc_error ("DATA statement at %L has more values than variables", + &d->where); +} + + +/* 12.6 Constraint: In a pure subprogram any variable which is in common or + accessed by host or use association, is a dummy argument to a pure function, + is a dummy argument with INTENT (IN) to a pure subroutine, or an object that + is storage associated with any such variable, shall not be used in the + following contexts: (clients of this function). */ + +/* Determines if a variable is not 'pure', i.e., 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) +{ + gfc_symbol *proc; + gfc_namespace *ns; + + if (sym->attr.use_assoc || sym->attr.in_common) + return 1; + + /* Check if the symbol's ns is inside the pure procedure. */ + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + if (ns == sym->ns) + break; + if (ns->proc_name->attr.flavor == FL_PROCEDURE && !sym->attr.function) + return 1; + } + + proc = sym->ns->proc_name; + if (sym->attr.dummy + && !sym->attr.value + && ((proc->attr.subroutine && sym->attr.intent == INTENT_IN) + || proc->attr.function)) + return 1; + + /* TODO: Sort out what can be storage associated, if anything, and include + it here. In principle equivalences should be scanned but it does not + seem to be possible to storage associate an impure variable this way. */ + return 0; +} + + +/* Test whether a symbol is pure or not. For a NULL pointer, checks if the + current namespace is inside a pure procedure. */ + +int +gfc_pure (gfc_symbol *sym) +{ + symbol_attribute attr; + gfc_namespace *ns; + + if (sym == NULL) + { + /* Check if the current namespace or one of its parents + belongs to a pure procedure. */ + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + sym = ns->proc_name; + if (sym == NULL) + return 0; + attr = sym->attr; + if (attr.flavor == FL_PROCEDURE && attr.pure) + return 1; + } + return 0; + } + + attr = sym->attr; + + return attr.flavor == FL_PROCEDURE && attr.pure; +} + + +/* Test whether a symbol is implicitly pure or not. For a NULL pointer, + checks if the current namespace is implicitly pure. Note that this + function returns false for a PURE procedure. */ + +int +gfc_implicit_pure (gfc_symbol *sym) +{ + gfc_namespace *ns; + + if (sym == NULL) + { + /* Check if the current procedure is implicit_pure. Walk up + the procedure list until we find a procedure. */ + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + sym = ns->proc_name; + if (sym == NULL) + return 0; + + if (sym->attr.flavor == FL_PROCEDURE) + break; + } + } + + return sym->attr.flavor == FL_PROCEDURE && sym->attr.implicit_pure + && !sym->attr.pure; +} + + +void +gfc_unset_implicit_pure (gfc_symbol *sym) +{ + gfc_namespace *ns; + + if (sym == NULL) + { + /* Check if the current procedure is implicit_pure. Walk up + the procedure list until we find a procedure. */ + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + sym = ns->proc_name; + if (sym == NULL) + return; + + if (sym->attr.flavor == FL_PROCEDURE) + break; + } + } + + if (sym->attr.flavor == FL_PROCEDURE) + sym->attr.implicit_pure = 0; + else + sym->attr.pure = 0; +} + + +/* 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_fortran_label (gfc_st_label *label) +{ + if (label == NULL) + return; + + warn_unused_fortran_label (label->left); + + if (label->defined == ST_LABEL_UNKNOWN) + return; + + switch (label->referenced) + { + case ST_LABEL_UNKNOWN: + gfc_warning (OPT_Wunused_label, "Label %d at %L defined but not used", + label->value, &label->where); + break; + + case ST_LABEL_BAD_TARGET: + gfc_warning (OPT_Wunused_label, + "Label %d at %L defined but cannot be used", + label->value, &label->where); + break; + + default: + break; + } + + warn_unused_fortran_label (label->right); +} + + +/* Returns the sequence type of a symbol or sequence. */ + +static seq_type +sequence_type (gfc_typespec ts) +{ + seq_type result; + gfc_component *c; + + switch (ts.type) + { + case BT_DERIVED: + + if (ts.u.derived->components == NULL) + return SEQ_NONDEFAULT; + + result = sequence_type (ts.u.derived->components->ts); + for (c = ts.u.derived->components->next; c; c = c->next) + if (sequence_type (c->ts) != result) + return SEQ_MIXED; + + return result; + + case BT_CHARACTER: + if (ts.kind != gfc_default_character_kind) + return SEQ_NONDEFAULT; + + return SEQ_CHARACTER; + + case BT_INTEGER: + if (ts.kind != gfc_default_integer_kind) + return SEQ_NONDEFAULT; + + return SEQ_NUMERIC; + + case BT_REAL: + if (!(ts.kind == gfc_default_real_kind + || ts.kind == gfc_default_double_kind)) + return SEQ_NONDEFAULT; + + return SEQ_NUMERIC; + + case BT_COMPLEX: + if (ts.kind != gfc_default_complex_kind) + return SEQ_NONDEFAULT; + + return SEQ_NUMERIC; + + case BT_LOGICAL: + if (ts.kind != gfc_default_logical_kind) + return SEQ_NONDEFAULT; + + return SEQ_NUMERIC; + + default: + return SEQ_NONDEFAULT; + } +} + + +/* Resolve derived type EQUIVALENCE object. */ + +static bool +resolve_equivalence_derived (gfc_symbol *derived, gfc_symbol *sym, gfc_expr *e) +{ + gfc_component *c = derived->components; + + if (!derived) + return true; + + /* Shall not be an object of nonsequence derived type. */ + if (!derived->attr.sequence) + { + gfc_error ("Derived type variable %qs at %L must have SEQUENCE " + "attribute to be an EQUIVALENCE object", sym->name, + &e->where); + return false; + } + + /* Shall not have allocatable components. */ + if (derived->attr.alloc_comp) + { + gfc_error ("Derived type variable %qs at %L cannot have ALLOCATABLE " + "components to be an EQUIVALENCE object",sym->name, + &e->where); + return false; + } + + if (sym->attr.in_common && gfc_has_default_initializer (sym->ts.u.derived)) + { + gfc_error ("Derived type variable %qs at %L with default " + "initialization cannot be in EQUIVALENCE with a variable " + "in COMMON", sym->name, &e->where); + return false; + } + + for (; c ; c = c->next) + { + if (gfc_bt_struct (c->ts.type) + && (!resolve_equivalence_derived(c->ts.u.derived, sym, e))) + return false; + + /* Shall not be an object of sequence derived type containing a pointer + in the structure. */ + if (c->attr.pointer) + { + gfc_error ("Derived type variable %qs at %L with pointer " + "component(s) cannot be an EQUIVALENCE object", + sym->name, &e->where); + return false; + } + } + return true; +} + + +/* Resolve equivalence object. + An EQUIVALENCE object shall not be a dummy argument, a pointer, a target, + 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. A substring shall not have length zero. A + derived type shall not have components with default initialization nor + shall two objects of an equivalence group be initialized. + Either all or none of the objects shall have an protected attribute. + The simple constraints are done in symbol.c(check_conflict) and the rest + are implemented here. */ + +static void +resolve_equivalence (gfc_equiv *eq) +{ + gfc_symbol *sym; + gfc_symbol *first_sym; + gfc_expr *e; + gfc_ref *r; + locus *last_where = NULL; + seq_type eq_type, last_eq_type; + gfc_typespec *last_ts; + int object, cnt_protected; + const char *msg; + + last_ts = &eq->expr->symtree->n.sym->ts; + + first_sym = eq->expr->symtree->n.sym; + + cnt_protected = 0; + + for (object = 1; eq; eq = eq->eq, object++) + { + e = eq->expr; + + e->ts = e->symtree->n.sym->ts; + /* match_varspec might not know yet if it is seeing + array reference or substring reference, as it doesn't + know the types. */ + if (e->ref && e->ref->type == REF_ARRAY) + { + gfc_ref *ref = e->ref; + sym = e->symtree->n.sym; + + if (sym->attr.dimension) + { + ref->u.ar.as = sym->as; + ref = ref->next; + } + + /* For substrings, convert REF_ARRAY into REF_SUBSTRING. */ + if (e->ts.type == BT_CHARACTER + && ref + && ref->type == REF_ARRAY + && ref->u.ar.dimen == 1 + && ref->u.ar.dimen_type[0] == DIMEN_RANGE + && ref->u.ar.stride[0] == NULL) + { + gfc_expr *start = ref->u.ar.start[0]; + gfc_expr *end = ref->u.ar.end[0]; + void *mem = NULL; + + /* Optimize away the (:) reference. */ + if (start == NULL && end == NULL) + { + if (e->ref == ref) + e->ref = ref->next; + else + e->ref->next = ref->next; + mem = ref; + } + else + { + ref->type = REF_SUBSTRING; + if (start == NULL) + start = gfc_get_int_expr (gfc_charlen_int_kind, + NULL, 1); + ref->u.ss.start = start; + if (end == NULL && e->ts.u.cl) + end = gfc_copy_expr (e->ts.u.cl->length); + ref->u.ss.end = end; + ref->u.ss.length = e->ts.u.cl; + e->ts.u.cl = NULL; + } + ref = ref->next; + free (mem); + } + + /* Any further ref is an error. */ + if (ref) + { + gcc_assert (ref->type == REF_ARRAY); + gfc_error ("Syntax error in EQUIVALENCE statement at %L", + &ref->u.ar.where); + continue; + } + } + + if (!gfc_resolve_expr (e)) + continue; + + sym = e->symtree->n.sym; + + if (sym->attr.is_protected) + cnt_protected++; + if (cnt_protected > 0 && cnt_protected != object) + { + gfc_error ("Either all or none of the objects in the " + "EQUIVALENCE set at %L shall have the " + "PROTECTED attribute", + &e->where); + break; + } + + /* Shall not equivalence common block variables in a PURE procedure. */ + if (sym->ns->proc_name + && sym->ns->proc_name->attr.pure + && sym->attr.in_common) + { + /* Need to check for symbols that may have entered the pure + procedure via a USE statement. */ + bool saw_sym = false; + if (sym->ns->use_stmts) + { + gfc_use_rename *r; + for (r = sym->ns->use_stmts->rename; r; r = r->next) + if (strcmp(r->use_name, sym->name) == 0) saw_sym = true; + } + else + saw_sym = true; + + if (saw_sym) + gfc_error ("COMMON block member %qs at %L cannot be an " + "EQUIVALENCE object in the pure procedure %qs", + sym->name, &e->where, sym->ns->proc_name->name); + break; + } + + /* Shall not be a named constant. */ + if (e->expr_type == EXPR_CONSTANT) + { + gfc_error ("Named constant %qs at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + if (e->ts.type == BT_DERIVED + && !resolve_equivalence_derived (e->ts.u.derived, sym, e)) + continue; + + /* Check that the types correspond correctly: + Note 5.28: + A numeric sequence structure may be equivalenced to another sequence + structure, an object of default integer type, default real type, double + precision real type, default logical type such that components of the + structure ultimately only become associated to objects of the same + kind. A character sequence structure may be equivalenced to an object + of default character kind or another character sequence structure. + Other objects may be equivalenced only to objects of the same type and + kind parameters. */ + + /* Identical types are unconditionally OK. */ + if (object == 1 || gfc_compare_types (last_ts, &sym->ts)) + goto identical_types; + + last_eq_type = sequence_type (*last_ts); + eq_type = sequence_type (sym->ts); + + /* Since the pair of objects is not of the same type, mixed or + non-default sequences can be rejected. */ + + msg = "Sequence %s with mixed components in EQUIVALENCE " + "statement at %L with different type objects"; + if ((object ==2 + && last_eq_type == SEQ_MIXED + && !gfc_notify_std (GFC_STD_GNU, msg, first_sym->name, last_where)) + || (eq_type == SEQ_MIXED + && !gfc_notify_std (GFC_STD_GNU, msg, sym->name, &e->where))) + continue; + + msg = "Non-default type object or sequence %s in EQUIVALENCE " + "statement at %L with objects of different type"; + if ((object ==2 + && last_eq_type == SEQ_NONDEFAULT + && !gfc_notify_std (GFC_STD_GNU, msg, first_sym->name, last_where)) + || (eq_type == SEQ_NONDEFAULT + && !gfc_notify_std (GFC_STD_GNU, msg, sym->name, &e->where))) + continue; + + msg ="Non-CHARACTER object %qs in default CHARACTER " + "EQUIVALENCE statement at %L"; + if (last_eq_type == SEQ_CHARACTER + && eq_type != SEQ_CHARACTER + && !gfc_notify_std (GFC_STD_GNU, msg, sym->name, &e->where)) + continue; + + msg ="Non-NUMERIC object %qs in default NUMERIC " + "EQUIVALENCE statement at %L"; + if (last_eq_type == SEQ_NUMERIC + && eq_type != SEQ_NUMERIC + && !gfc_notify_std (GFC_STD_GNU, msg, sym->name, &e->where)) + continue; + +identical_types: + + last_ts =&sym->ts; + last_where = &e->where; + + if (!e->ref) + continue; + + /* Shall not be an automatic array. */ + if (e->ref->type == REF_ARRAY && is_non_constant_shape_array (sym)) + { + gfc_error ("Array %qs at %L with non-constant bounds cannot be " + "an EQUIVALENCE object", sym->name, &e->where); + continue; + } + + r = e->ref; + while (r) + { + /* Shall not be a structure component. */ + if (r->type == REF_COMPONENT) + { + gfc_error ("Structure component %qs at %L cannot be an " + "EQUIVALENCE object", + r->u.c.component->name, &e->where); + break; + } + + /* A substring shall not have length zero. */ + if (r->type == REF_SUBSTRING) + { + if (compare_bound (r->u.ss.start, r->u.ss.end) == CMP_GT) + { + gfc_error ("Substring at %L has length zero", + &r->u.ss.start->where); + break; + } + } + r = r->next; + } + } +} + + +/* Function called by resolve_fntype to flag other symbols used in the + length type parameter specification of function results. */ + +static bool +flag_fn_result_spec (gfc_expr *expr, + gfc_symbol *sym, + int *f ATTRIBUTE_UNUSED) +{ + gfc_namespace *ns; + gfc_symbol *s; + + if (expr->expr_type == EXPR_VARIABLE) + { + s = expr->symtree->n.sym; + for (ns = s->ns; ns; ns = ns->parent) + if (!ns->parent) + break; + + if (sym == s) + { + gfc_error ("Self reference in character length expression " + "for %qs at %L", sym->name, &expr->where); + return true; + } + + if (!s->fn_result_spec + && s->attr.flavor == FL_PARAMETER) + { + /* Function contained in a module.... */ + if (ns->proc_name && ns->proc_name->attr.flavor == FL_MODULE) + { + gfc_symtree *st; + s->fn_result_spec = 1; + /* Make sure that this symbol is translated as a module + variable. */ + st = gfc_get_unique_symtree (ns); + st->n.sym = s; + s->refs++; + } + /* ... which is use associated and called. */ + else if (s->attr.use_assoc || s->attr.used_in_submodule + || + /* External function matched with an interface. */ + (s->ns->proc_name + && ((s->ns == ns + && s->ns->proc_name->attr.if_source == IFSRC_DECL) + || s->ns->proc_name->attr.if_source == IFSRC_IFBODY) + && s->ns->proc_name->attr.function)) + s->fn_result_spec = 1; + } + } + return false; +} + + +/* Resolve function and ENTRY types, issue diagnostics if needed. */ + +static void +resolve_fntype (gfc_namespace *ns) +{ + gfc_entry_list *el; + gfc_symbol *sym; + + if (ns->proc_name == NULL || !ns->proc_name->attr.function) + return; + + /* If there are any entries, ns->proc_name is the entry master + synthetic symbol and ns->entries->sym actual FUNCTION symbol. */ + if (ns->entries) + sym = ns->entries->sym; + else + sym = ns->proc_name; + if (sym->result == sym + && sym->ts.type == BT_UNKNOWN + && !gfc_set_default_type (sym, 0, NULL) + && !sym->attr.untyped) + { + gfc_error ("Function %qs at %L has no IMPLICIT type", + sym->name, &sym->declared_at); + sym->attr.untyped = 1; + } + + if (sym->ts.type == BT_DERIVED && !sym->ts.u.derived->attr.use_assoc + && !sym->attr.contained + && !gfc_check_symbol_access (sym->ts.u.derived) + && gfc_check_symbol_access (sym)) + { + gfc_notify_std (GFC_STD_F2003, "PUBLIC function %qs at " + "%L of PRIVATE type %qs", sym->name, + &sym->declared_at, sym->ts.u.derived->name); + } + + if (ns->entries) + for (el = ns->entries->next; el; el = el->next) + { + if (el->sym->result == el->sym + && el->sym->ts.type == BT_UNKNOWN + && !gfc_set_default_type (el->sym, 0, NULL) + && !el->sym->attr.untyped) + { + gfc_error ("ENTRY %qs at %L has no IMPLICIT type", + el->sym->name, &el->sym->declared_at); + el->sym->attr.untyped = 1; + } + } + + if (sym->ts.type == BT_CHARACTER) + gfc_traverse_expr (sym->ts.u.cl->length, sym, flag_fn_result_spec, 0); +} + + +/* 12.3.2.1.1 Defined operators. */ + +static bool +check_uop_procedure (gfc_symbol *sym, locus where) +{ + gfc_formal_arglist *formal; + + if (!sym->attr.function) + { + gfc_error ("User operator procedure %qs at %L must be a FUNCTION", + sym->name, &where); + return false; + } + + if (sym->ts.type == BT_CHARACTER + && !((sym->ts.u.cl && sym->ts.u.cl->length) || sym->ts.deferred) + && !(sym->result && ((sym->result->ts.u.cl + && sym->result->ts.u.cl->length) || sym->result->ts.deferred))) + { + gfc_error ("User operator procedure %qs at %L cannot be assumed " + "character length", sym->name, &where); + return false; + } + + formal = gfc_sym_get_dummy_args (sym); + if (!formal || !formal->sym) + { + gfc_error ("User operator procedure %qs at %L must have at least " + "one argument", sym->name, &where); + return false; + } + + if (formal->sym->attr.intent != INTENT_IN) + { + gfc_error ("First argument of operator interface at %L must be " + "INTENT(IN)", &where); + return false; + } + + if (formal->sym->attr.optional) + { + gfc_error ("First argument of operator interface at %L cannot be " + "optional", &where); + return false; + } + + formal = formal->next; + if (!formal || !formal->sym) + return true; + + if (formal->sym->attr.intent != INTENT_IN) + { + gfc_error ("Second argument of operator interface at %L must be " + "INTENT(IN)", &where); + return false; + } + + if (formal->sym->attr.optional) + { + gfc_error ("Second argument of operator interface at %L cannot be " + "optional", &where); + return false; + } + + if (formal->next) + { + gfc_error ("Operator interface at %L must have, at most, two " + "arguments", &where); + return false; + } + + return true; +} + +static void +gfc_resolve_uops (gfc_symtree *symtree) +{ + gfc_interface *itr; + + if (symtree == NULL) + return; + + gfc_resolve_uops (symtree->left); + gfc_resolve_uops (symtree->right); + + for (itr = symtree->n.uop->op; itr; itr = itr->next) + check_uop_procedure (itr->sym, itr->sym->declared_at); +} + + +/* 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. It doesn't check code + block, which is handled by gfc_resolve_code. */ + +static void +resolve_types (gfc_namespace *ns) +{ + gfc_namespace *n; + gfc_charlen *cl; + gfc_data *d; + gfc_equiv *eq; + gfc_namespace* old_ns = gfc_current_ns; + bool recursive = ns->proc_name && ns->proc_name->attr.recursive; + + if (ns->types_resolved) + return; + + /* Check that all IMPLICIT types are ok. */ + if (!ns->seen_implicit_none) + { + unsigned letter; + for (letter = 0; letter != GFC_LETTERS; ++letter) + if (ns->set_flag[letter] + && !resolve_typespec_used (&ns->default_type[letter], + &ns->implicit_loc[letter], NULL)) + return; + } + + gfc_current_ns = ns; + + resolve_entries (ns); + + resolve_common_vars (&ns->blank_common, false); + resolve_common_blocks (ns->common_root); + + resolve_contained_functions (ns); + + if (ns->proc_name && ns->proc_name->attr.flavor == FL_PROCEDURE + && ns->proc_name->attr.if_source == IFSRC_IFBODY) + gfc_resolve_formal_arglist (ns->proc_name); + + gfc_traverse_ns (ns, resolve_bind_c_derived_types); + + for (cl = ns->cl_list; cl; cl = cl->next) + resolve_charlen (cl); + + gfc_traverse_ns (ns, resolve_symbol); + + resolve_fntype (ns); + + for (n = ns->contained; n; n = n->sibling) + { + if (gfc_pure (ns->proc_name) && !gfc_pure (n->proc_name)) + gfc_error ("Contained procedure %qs at %L of a PURE procedure must " + "also be PURE", n->proc_name->name, + &n->proc_name->declared_at); + + resolve_types (n); + } + + forall_flag = 0; + gfc_do_concurrent_flag = 0; + gfc_check_interfaces (ns); + + gfc_traverse_ns (ns, resolve_values); + + if (ns->save_all || (!flag_automatic && !recursive)) + 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); + + gfc_traverse_ns (ns, gfc_verify_binding_labels); + + for (eq = ns->equiv; eq; eq = eq->next) + resolve_equivalence (eq); + + /* Warn about unused labels. */ + if (warn_unused_label) + warn_unused_fortran_label (ns->st_labels); + + gfc_resolve_uops (ns->uop_root); + + gfc_traverse_ns (ns, gfc_verify_DTIO_procedures); + + gfc_resolve_omp_declare_simd (ns); + + gfc_resolve_omp_udrs (ns->omp_udr_root); + + ns->types_resolved = 1; + + gfc_current_ns = old_ns; +} + + +/* Call gfc_resolve_code recursively. */ + +static void +resolve_codes (gfc_namespace *ns) +{ + gfc_namespace *n; + bitmap_obstack old_obstack; + + if (ns->resolved == 1) + return; + + for (n = ns->contained; n; n = n->sibling) + resolve_codes (n); + + gfc_current_ns = ns; + + /* Don't clear 'cs_base' if this is the namespace of a BLOCK construct. */ + if (!(ns->proc_name && ns->proc_name->attr.flavor == FL_LABEL)) + cs_base = NULL; + + /* Set to an out of range value. */ + current_entry_id = -1; + + old_obstack = labels_obstack; + bitmap_obstack_initialize (&labels_obstack); + + gfc_resolve_oacc_declare (ns); + gfc_resolve_oacc_routines (ns); + gfc_resolve_omp_local_vars (ns); + gfc_resolve_code (ns->code, ns); + + bitmap_obstack_release (&labels_obstack); + labels_obstack = old_obstack; +} + + +/* 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; + code_stack *old_cs_base; + struct gfc_omp_saved_state old_omp_state; + + if (ns->resolved) + return; + + ns->resolved = -1; + old_ns = gfc_current_ns; + old_cs_base = cs_base; + + /* As gfc_resolve can be called during resolution of an OpenMP construct + body, we should clear any state associated to it, so that say NS's + DO loops are not interpreted as OpenMP loops. */ + if (!ns->construct_entities) + gfc_omp_save_and_clear_state (&old_omp_state); + + resolve_types (ns); + component_assignment_level = 0; + resolve_codes (ns); + + gfc_current_ns = old_ns; + cs_base = old_cs_base; + ns->resolved = 1; + + gfc_run_passes (ns); + + if (!ns->construct_entities) + gfc_omp_restore_state (&old_omp_state); +} |