/* Perform type resolution on the various structures.
Copyright (C) 2001-2020 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
. */
#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= is also possible, but difficult to
check at compile time. */
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);
}
}
}
}
}
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;
for (; csym; csym = csym->common_next)
{
/* 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 in cannot appear in COMMON at %L "
"[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;
};
if (cons->expr->shape == NULL)
continue;
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))
{
gfc_warning (OPT_Wpedantic,
"%qs at %L is an array and OPTIONAL; IF IT IS "
"MISSING, it cannot be the actual argument of an "
"ELEMENTAL procedure unless there is a non-optional "
"argument with the same rank (12.4.1.5)",
arg->expr->symtree->n.sym->name, &arg->expr->where);
}
}
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);
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;
}
/* 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;
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;
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))
return 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;
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 ("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 ("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 = "Equality comparison for %s at %L";
else
msg = "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
|| a->ts.type != BT_INTEGER)
return CMP_UNKNOWN;
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
|| a->ts.type != BT_INTEGER)
return CMP_UNKNOWN;
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);
compare_result comp_stride_zero = compare_bound_int (ar->stride[i], 0);
/* Check for zero stride, which is not allowed. */
if (comp_stride_zero == CMP_EQ)
{
gfc_error ("Illegal stride of zero at %L", &ar->c_where[i]);
return false;
}
/* if start == end || (stride > 0 && start < end)
|| (stride < 0 && start > end),
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 (comp_start_end == CMP_EQ
|| ((comp_stride_zero == CMP_GT || ar->stride[i] == NULL)
&& comp_start_end == CMP_LT)
|| (comp_stride_zero == 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;
}
e->ts.type = BT_CHARACTER;
e->ts.kind = gfc_default_character_kind;
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 = *gfc_get_array_ref();
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);
/* 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;
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 || c->attr.allocatable)
&& 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. */
if (allocatable == 0 && pointer == 0 && !unlimited)
{
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)
{
gfc_check_vardef_context (stat, false, false, false,
_("STAT variable"));
if ((stat->ts.type != BT_INTEGER
&& !(stat->ref && (stat->ref->type == REF_ARRAY
|| stat->ref->type == REF_COMPONENT)))
|| stat->rank > 0)
gfc_error ("Stat-variable at %L must be a scalar INTEGER "
"variable", &stat->where);
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;
}
}
}
/* Check the errmsg variable. */
if (errmsg)
{
if (!stat)
gfc_warning (0, "ERRMSG at %L is useless without a STAT tag",
&errmsg->where);
gfc_check_vardef_context (errmsg, false, false, false,
_("ERRMSG variable"));
/* 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->ref
&& (errmsg->ref->type == REF_ARRAY
|| errmsg->ref->type == REF_COMPONENT)))
|| 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);
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;
}
}
}
/* 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; idimen; 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, 2, 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, 2, 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->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
&& 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)
{
if (!sym->ts.deferred)
{
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;
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
&& (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);
/* Check ERRMSG. */
gfc_resolve_expr (code->expr3);
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);
}
/* 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; irank; 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:
{
gfc_omp_atomic_op aop
= (gfc_omp_atomic_op) (b->ext.omp_atomic & GFC_OMP_ATOMIC_MASK);
/* Verify this before calling gfc_resolve_code, which might
change it. */
gcc_assert (b->next && b->next->op == EXEC_ASSIGN);
gcc_assert (((aop != GFC_OMP_ATOMIC_CAPTURE)
&& b->next->next == NULL)
|| ((aop == GFC_OMP_ATOMIC_CAPTURE)
&& b->next->next != NULL
&& b->next->next->op == EXEC_ASSIGN
&& b->next->next->next == NULL));
}
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_MASTER:
case EXEC_OMP_ORDERED:
case EXEC_OMP_PARALLEL:
case EXEC_OMP_PARALLEL_DO:
case EXEC_OMP_PARALLEL_DO_SIMD:
case EXEC_OMP_PARALLEL_SECTIONS:
case EXEC_OMP_PARALLEL_WORKSHARE:
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_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_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_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.result = 0;
tmp->n.sym->attr.flavor = FL_VARIABLE;
tmp->n.sym->attr.dummy = 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)->expr2, 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_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 (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->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)->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_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_MASTER:
case EXEC_OMP_ORDERED:
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_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_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_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_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->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)
|| (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->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
&& !(sym->ts.type == BT_DERIVED && sym->attr.intent == INTENT_OUT))
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;
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);
}
}
}
/* F2018:15.4.2.2 requires an explicit interface for procedures with the
BIND(C) attribute. */
if (sym->attr.is_bind_c && sym->attr.if_source == IFSRC_UNKNOWN)
{
gfc_error ("Interface of %qs at %L must be explicit",
sym->name, &sym->declared_at);
return false;
}
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.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.u.cl->length && c->ts.u.cl->length->ts.type != BT_INTEGER)
{
if (!c->ts.u.cl->length->error)
{
gfc_error ("Character length expression of component %qs at %L "
"must be of INTEGER type, found %s",
c->name, &c->ts.u.cl->length->where,
gfc_basic_typename (c->ts.u.cl->length->ts.type));
c->ts.u.cl->length->error = 1;
}
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 (!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;
specification_expr = true;
gfc_resolve_array_spec (sym->result->as, false);
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; irank; 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 && sym->ns->proc_name->attr.flavor == FL_MODULE)
&& !sym->attr.in_common)
{
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->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)))
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)))
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->intent == INTENT_OUT && !a->pointer))
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
&& !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 (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
&& sym->ts.u.cl->length
&& sym->ts.u.cl->length->ts.type == BT_INTEGER)
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);
}