/* Deal with interfaces.
- Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010
Free Software Foundation, Inc.
Contributed by Andy Vaught
{
if (current_interface.op == INTRINSIC_ASSIGN)
- gfc_error ("Expected 'END INTERFACE ASSIGNMENT (=)' at %C");
+ {
+ m = MATCH_ERROR;
+ gfc_error ("Expected 'END INTERFACE ASSIGNMENT (=)' at %C");
+ }
else
- gfc_error ("Expecting 'END INTERFACE OPERATOR (%s)' at %C",
- gfc_op2string (current_interface.op));
+ {
+ char *s1, *s2;
+ s1 = gfc_op2string (current_interface.op);
+ s2 = gfc_op2string (op);
+
+ /* The following if-statements are used to enforce C1202
+ from F2003. */
+ if ((strcmp(s1, "==") == 0 && strcmp(s2, ".eq.") == 0)
+ || (strcmp(s1, ".eq.") == 0 && strcmp(s2, "==") == 0))
+ break;
+ if ((strcmp(s1, "/=") == 0 && strcmp(s2, ".ne.") == 0)
+ || (strcmp(s1, ".ne.") == 0 && strcmp(s2, "/=") == 0))
+ break;
+ if ((strcmp(s1, "<=") == 0 && strcmp(s2, ".le.") == 0)
+ || (strcmp(s1, ".le.") == 0 && strcmp(s2, "<=") == 0))
+ break;
+ if ((strcmp(s1, "<") == 0 && strcmp(s2, ".lt.") == 0)
+ || (strcmp(s1, ".lt.") == 0 && strcmp(s2, "<") == 0))
+ break;
+ if ((strcmp(s1, ">=") == 0 && strcmp(s2, ".ge.") == 0)
+ || (strcmp(s1, ".ge.") == 0 && strcmp(s2, ">=") == 0))
+ break;
+ if ((strcmp(s1, ">") == 0 && strcmp(s2, ".gt.") == 0)
+ || (strcmp(s1, ".gt.") == 0 && strcmp(s2, ">") == 0))
+ break;
- m = MATCH_ERROR;
+ m = MATCH_ERROR;
+ gfc_error ("Expecting 'END INTERFACE OPERATOR (%s)' at %C, "
+ "but got %s", s1, s2);
+ }
+
}
break;
{
gfc_component *dt1, *dt2;
+ if (derived1 == derived2)
+ return 1;
+
/* Special case for comparing derived types across namespaces. If the
true names and module names are the same and the module name is
nonnull, then they are equal. */
/* Make sure that link lists do not put this function into an
endless recursive loop! */
- if (!(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.derived)
- && !(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.derived)
+ if (!(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.u.derived)
+ && !(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.u.derived)
&& gfc_compare_types (&dt1->ts, &dt2->ts) == 0)
return 0;
- else if ((dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.derived)
- && !(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.derived))
+ else if ((dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.u.derived)
+ && !(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.u.derived))
return 0;
- else if (!(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.derived)
- && (dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.derived))
+ else if (!(dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.u.derived)
+ && (dt1->ts.type == BT_DERIVED && derived1 == dt1->ts.u.derived))
return 0;
dt1 = dt1->next;
if (ts1->type == BT_VOID || ts2->type == BT_VOID)
return 1;
- if (ts1->type != ts2->type)
+ if (ts1->type != ts2->type
+ && ((ts1->type != BT_DERIVED && ts1->type != BT_CLASS)
+ || (ts2->type != BT_DERIVED && ts2->type != BT_CLASS)))
return 0;
- if (ts1->type != BT_DERIVED)
+ if (ts1->type != BT_DERIVED && ts1->type != BT_CLASS)
return (ts1->kind == ts2->kind);
/* Compare derived types. */
- if (ts1->derived == ts2->derived)
+ if (gfc_type_compatible (ts1, ts2))
return 1;
- return gfc_compare_derived_types (ts1->derived ,ts2->derived);
+ return gfc_compare_derived_types (ts1->u.derived ,ts2->u.derived);
}
/* Given an operator interface and the operator, make sure that all
interfaces for that operator are legal. */
-static void
-check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
+bool
+gfc_check_operator_interface (gfc_symbol *sym, gfc_intrinsic_op op,
+ locus opwhere)
{
gfc_formal_arglist *formal;
sym_intent i1, i2;
- gfc_symbol *sym;
bt t1, t2;
int args, r1, r2, k1, k2;
- if (intr == NULL)
- return;
+ gcc_assert (sym);
args = 0;
t1 = t2 = BT_UNKNOWN;
r1 = r2 = -1;
k1 = k2 = -1;
- for (formal = intr->sym->formal; formal; formal = formal->next)
+ for (formal = sym->formal; formal; formal = formal->next)
{
- sym = formal->sym;
- if (sym == NULL)
+ gfc_symbol *fsym = formal->sym;
+ if (fsym == NULL)
{
gfc_error ("Alternate return cannot appear in operator "
- "interface at %L", &intr->sym->declared_at);
- return;
+ "interface at %L", &sym->declared_at);
+ return false;
}
if (args == 0)
{
- t1 = sym->ts.type;
- i1 = sym->attr.intent;
- r1 = (sym->as != NULL) ? sym->as->rank : 0;
- k1 = sym->ts.kind;
+ t1 = fsym->ts.type;
+ i1 = fsym->attr.intent;
+ r1 = (fsym->as != NULL) ? fsym->as->rank : 0;
+ k1 = fsym->ts.kind;
}
if (args == 1)
{
- t2 = sym->ts.type;
- i2 = sym->attr.intent;
- r2 = (sym->as != NULL) ? sym->as->rank : 0;
- k2 = sym->ts.kind;
+ t2 = fsym->ts.type;
+ i2 = fsym->attr.intent;
+ r2 = (fsym->as != NULL) ? fsym->as->rank : 0;
+ k2 = fsym->ts.kind;
}
args++;
}
- sym = intr->sym;
-
/* Only +, - and .not. can be unary operators.
.not. cannot be a binary operator. */
if (args == 0 || args > 2 || (args == 1 && op != INTRINSIC_PLUS
|| (args == 2 && op == INTRINSIC_NOT))
{
gfc_error ("Operator interface at %L has the wrong number of arguments",
- &intr->sym->declared_at);
- return;
+ &sym->declared_at);
+ return false;
}
/* Check that intrinsics are mapped to functions, except
if (!sym->attr.subroutine)
{
gfc_error ("Assignment operator interface at %L must be "
- "a SUBROUTINE", &intr->sym->declared_at);
- return;
+ "a SUBROUTINE", &sym->declared_at);
+ return false;
}
if (args != 2)
{
gfc_error ("Assignment operator interface at %L must have "
- "two arguments", &intr->sym->declared_at);
- return;
+ "two arguments", &sym->declared_at);
+ return false;
}
/* Allowed are (per F2003, 12.3.2.1.2 Defined assignments):
- - First argument an array with different rank than second,
- - Types and kinds do not conform, and
- - First argument is of derived type. */
+ - First argument an array with different rank than second,
+ - Types and kinds do not conform, and
+ - First argument is of derived type. */
if (sym->formal->sym->ts.type != BT_DERIVED
+ && sym->formal->sym->ts.type != BT_CLASS
&& (r1 == 0 || r1 == r2)
&& (sym->formal->sym->ts.type == sym->formal->next->sym->ts.type
|| (gfc_numeric_ts (&sym->formal->sym->ts)
&& gfc_numeric_ts (&sym->formal->next->sym->ts))))
{
gfc_error ("Assignment operator interface at %L must not redefine "
- "an INTRINSIC type assignment", &intr->sym->declared_at);
- return;
+ "an INTRINSIC type assignment", &sym->declared_at);
+ return false;
}
}
else
if (!sym->attr.function)
{
gfc_error ("Intrinsic operator interface at %L must be a FUNCTION",
- &intr->sym->declared_at);
- return;
+ &sym->declared_at);
+ return false;
}
}
if (op == INTRINSIC_ASSIGN)
{
if (i1 != INTENT_OUT && i1 != INTENT_INOUT)
- gfc_error ("First argument of defined assignment at %L must be "
- "INTENT(OUT) or INTENT(INOUT)", &intr->sym->declared_at);
+ {
+ gfc_error ("First argument of defined assignment at %L must be "
+ "INTENT(OUT) or INTENT(INOUT)", &sym->declared_at);
+ return false;
+ }
if (i2 != INTENT_IN)
- gfc_error ("Second argument of defined assignment at %L must be "
- "INTENT(IN)", &intr->sym->declared_at);
+ {
+ gfc_error ("Second argument of defined assignment at %L must be "
+ "INTENT(IN)", &sym->declared_at);
+ return false;
+ }
}
else
{
if (i1 != INTENT_IN)
- gfc_error ("First argument of operator interface at %L must be "
- "INTENT(IN)", &intr->sym->declared_at);
+ {
+ gfc_error ("First argument of operator interface at %L must be "
+ "INTENT(IN)", &sym->declared_at);
+ return false;
+ }
if (args == 2 && i2 != INTENT_IN)
- gfc_error ("Second argument of operator interface at %L must be "
- "INTENT(IN)", &intr->sym->declared_at);
+ {
+ gfc_error ("Second argument of operator interface at %L must be "
+ "INTENT(IN)", &sym->declared_at);
+ return false;
+ }
}
/* From now on, all we have to do is check that the operator definition
if (t1 == BT_LOGICAL)
goto bad_repl;
else
- return;
+ return true;
}
if (args == 1 && (op == INTRINSIC_PLUS || op == INTRINSIC_MINUS))
if (IS_NUMERIC_TYPE (t1))
goto bad_repl;
else
- return;
+ return true;
}
/* Character intrinsic operators have same character kind, thus
operator definitions with operands of different character kinds
are always safe. */
if (t1 == BT_CHARACTER && t2 == BT_CHARACTER && k1 != k2)
- return;
+ return true;
/* Intrinsic operators always perform on arguments of same rank,
so different ranks is also always safe. (rank == 0) is an exception
to that, because all intrinsic operators are elemental. */
if (r1 != r2 && r1 != 0 && r2 != 0)
- return;
+ return true;
switch (op)
{
break;
}
- return;
+ return true;
#undef IS_NUMERIC_TYPE
bad_repl:
gfc_error ("Operator interface at %L conflicts with intrinsic interface",
- &intr->where);
- return;
+ &opwhere);
+ return false;
}
required to match, which is not the case for ambiguity checks.*/
int
-gfc_compare_interfaces (gfc_symbol *s1, gfc_symbol *s2, int generic_flag,
- int intent_flag, char *errmsg, int err_len)
+gfc_compare_interfaces (gfc_symbol *s1, gfc_symbol *s2, const char *name2,
+ int generic_flag, int intent_flag,
+ char *errmsg, int err_len)
{
gfc_formal_arglist *f1, *f2;
+ gcc_assert (name2 != NULL);
+
if (s1->attr.function && (s2->attr.subroutine
|| (!s2->attr.function && s2->ts.type == BT_UNKNOWN
- && gfc_get_default_type (s2->name, s2->ns)->type == BT_UNKNOWN)))
+ && gfc_get_default_type (name2, s2->ns)->type == BT_UNKNOWN)))
{
if (errmsg != NULL)
- snprintf (errmsg, err_len, "'%s' is not a function", s2->name);
+ snprintf (errmsg, err_len, "'%s' is not a function", name2);
return 0;
}
if (s1->attr.subroutine && s2->attr.function)
{
if (errmsg != NULL)
- snprintf (errmsg, err_len, "'%s' is not a subroutine", s2->name);
+ snprintf (errmsg, err_len, "'%s' is not a subroutine", name2);
return 0;
}
/* If the arguments are functions, check type and kind
(only for dummy procedures and procedure pointer assignments). */
- if ((s1->attr.dummy || s1->attr.proc_pointer)
- && s1->attr.function && s2->attr.function)
+ if (!generic_flag && intent_flag && s1->attr.function && s2->attr.function)
{
if (s1->ts.type == BT_UNKNOWN)
return 1;
{
if (errmsg != NULL)
snprintf (errmsg, err_len, "Type/kind mismatch in return value "
- "of '%s'", s2->name);
+ "of '%s'", name2);
return 0;
}
}
if (generic_flag)
{
+ if (count_types_test (f1, f2) || count_types_test (f2, f1))
+ return 0;
if (generic_correspondence (f1, f2) || generic_correspondence (f2, f1))
return 0;
}
{
if (errmsg != NULL)
snprintf (errmsg, err_len, "'%s' has the wrong number of "
- "arguments", s2->name);
+ "arguments", name2);
return 0;
}
f2 = f2->next;
}
- if (count_types_test (f1, f2) || count_types_test (f2, f1))
- {
- if (errmsg != NULL)
- snprintf (errmsg, err_len, "Interface not matching");
- return 0;
- }
-
return 1;
}
if (p->sym->name == q->sym->name && p->sym->module == q->sym->module)
continue;
- if (gfc_compare_interfaces (p->sym, q->sym, generic_flag, 0, NULL, 0))
+ if (gfc_compare_interfaces (p->sym, q->sym, q->sym->name, generic_flag,
+ 0, NULL, 0))
{
if (referenced)
- {
- gfc_error ("Ambiguous interfaces '%s' and '%s' in %s at %L",
- p->sym->name, q->sym->name, interface_name,
- &p->where);
- }
-
- if (!p->sym->attr.use_assoc && q->sym->attr.use_assoc)
+ gfc_error ("Ambiguous interfaces '%s' and '%s' in %s at %L",
+ p->sym->name, q->sym->name, interface_name,
+ &p->where);
+ else if (!p->sym->attr.use_assoc && q->sym->attr.use_assoc)
gfc_warning ("Ambiguous interfaces '%s' and '%s' in %s at %L",
p->sym->name, q->sym->name, interface_name,
&p->where);
+ else
+ gfc_warning ("Although not referenced, '%s' has ambiguous "
+ "interfaces at %L", interface_name, &p->where);
return 1;
}
}
check_sym_interfaces (gfc_symbol *sym)
{
char interface_name[100];
- bool k;
gfc_interface *p;
if (sym->ns != gfc_current_ns)
/* Originally, this test was applied to host interfaces too;
this is incorrect since host associated symbols, from any
source, cannot be ambiguous with local symbols. */
- k = sym->attr.referenced || !sym->attr.use_assoc;
- if (check_interface1 (sym->generic, sym->generic, 1, interface_name, k))
- sym->attr.ambiguous_interfaces = 1;
+ check_interface1 (sym->generic, sym->generic, 1, interface_name,
+ sym->attr.referenced || !sym->attr.use_assoc);
}
}
if (check_interface0 (ns->op[i], interface_name))
continue;
- check_operator_interface (ns->op[i], (gfc_intrinsic_op) i);
+ if (ns->op[i])
+ gfc_check_operator_interface (ns->op[i]->sym, (gfc_intrinsic_op) i,
+ ns->op[i]->where);
for (ns2 = ns; ns2; ns2 = ns2->parent)
{
if (formal->attr.pointer)
{
attr = gfc_expr_attr (actual);
+
+ /* Fortran 2008 allows non-pointer actual arguments. */
+ if (!attr.pointer && attr.target && formal->attr.intent == INTENT_IN)
+ return 2;
+
if (!attr.pointer)
return 0;
}
}
+/* Emit clear error messages for rank mismatch. */
+
+static void
+argument_rank_mismatch (const char *name, locus *where,
+ int rank1, int rank2)
+{
+ if (rank1 == 0)
+ {
+ gfc_error ("Rank mismatch in argument '%s' at %L "
+ "(scalar and rank-%d)", name, where, rank2);
+ }
+ else if (rank2 == 0)
+ {
+ gfc_error ("Rank mismatch in argument '%s' at %L "
+ "(rank-%d and scalar)", name, where, rank1);
+ }
+ else
+ {
+ gfc_error ("Rank mismatch in argument '%s' at %L "
+ "(rank-%d and rank-%d)", name, where, rank1, rank2);
+ }
+}
+
+
/* Given a symbol of a formal argument list and an expression, see if
the two are compatible as arguments. Returns nonzero if
compatible, zero if not compatible. */
return 1;
if (formal->ts.type == BT_DERIVED
- && formal->ts.derived && formal->ts.derived->ts.is_iso_c
+ && formal->ts.u.derived && formal->ts.u.derived->ts.is_iso_c
&& actual->ts.type == BT_DERIVED
- && actual->ts.derived && actual->ts.derived->ts.is_iso_c)
+ && actual->ts.u.derived && actual->ts.u.derived->ts.is_iso_c)
return 1;
+ if (formal->ts.type == BT_CLASS && actual->ts.type == BT_DERIVED)
+ /* Make sure the vtab symbol is present when
+ the module variables are generated. */
+ gfc_find_derived_vtab (actual->ts.u.derived);
+
if (actual->ts.type == BT_PROCEDURE)
{
char err[200];
return 0;
}
- if (!gfc_compare_interfaces (formal, act_sym, 0, 1, err,
+ if (!gfc_compare_interfaces (formal, act_sym, act_sym->name, 0, 1, err,
sizeof(err)))
{
if (where)
return 1;
}
+ /* F2008, C1241. */
+ if (formal->attr.pointer && formal->attr.contiguous
+ && !gfc_is_simply_contiguous (actual, true))
+ {
+ if (where)
+ gfc_error ("Actual argument to contiguous pointer dummy '%s' at %L "
+ "must be simply contigous", formal->name, &actual->where);
+ return 0;
+ }
+
if ((actual->expr_type != EXPR_NULL || actual->ts.type != BT_UNKNOWN)
+ && actual->ts.type != BT_HOLLERITH
&& !gfc_compare_types (&formal->ts, &actual->ts))
{
if (where)
return 0;
}
+ if (formal->attr.codimension)
+ {
+ gfc_ref *last = NULL;
+
+ if (actual->expr_type != EXPR_VARIABLE
+ || (actual->ref == NULL
+ && !actual->symtree->n.sym->attr.codimension))
+ {
+ if (where)
+ gfc_error ("Actual argument to '%s' at %L must be a coarray",
+ formal->name, &actual->where);
+ return 0;
+ }
+
+ for (ref = actual->ref; ref; ref = ref->next)
+ {
+ if (ref->type == REF_ARRAY && ref->u.ar.codimen != 0)
+ {
+ if (where)
+ gfc_error ("Actual argument to '%s' at %L must be a coarray "
+ "and not coindexed", formal->name, &ref->u.ar.where);
+ return 0;
+ }
+ if (ref->type == REF_ARRAY && ref->u.ar.as->corank
+ && ref->u.ar.type != AR_FULL && ref->u.ar.dimen != 0)
+ {
+ if (where)
+ gfc_error ("Actual argument to '%s' at %L must be a coarray "
+ "and thus shall not have an array designator",
+ formal->name, &ref->u.ar.where);
+ return 0;
+ }
+ if (ref->type == REF_COMPONENT)
+ last = ref;
+ }
+
+ if (last && !last->u.c.component->attr.codimension)
+ {
+ if (where)
+ gfc_error ("Actual argument to '%s' at %L must be a coarray",
+ formal->name, &actual->where);
+ return 0;
+ }
+
+ /* F2008, 12.5.2.6. */
+ if (formal->attr.allocatable &&
+ ((last && last->u.c.component->as->corank != formal->as->corank)
+ || (!last
+ && actual->symtree->n.sym->as->corank != formal->as->corank)))
+ {
+ if (where)
+ gfc_error ("Corank mismatch in argument '%s' at %L (%d and %d)",
+ formal->name, &actual->where, formal->as->corank,
+ last ? last->u.c.component->as->corank
+ : actual->symtree->n.sym->as->corank);
+ return 0;
+ }
+
+ /* F2008, 12.5.2.8. */
+ if (formal->attr.dimension
+ && (formal->attr.contiguous || formal->as->type != AS_ASSUMED_SHAPE)
+ && !gfc_is_simply_contiguous (actual, true))
+ {
+ if (where)
+ gfc_error ("Actual argument to '%s' at %L must be simply "
+ "contiguous", formal->name, &actual->where);
+ return 0;
+ }
+ }
+
+ /* F2008, C1239/C1240. */
+ if (actual->expr_type == EXPR_VARIABLE
+ && (actual->symtree->n.sym->attr.asynchronous
+ || actual->symtree->n.sym->attr.volatile_)
+ && (formal->attr.asynchronous || formal->attr.volatile_)
+ && actual->rank && !gfc_is_simply_contiguous (actual, true)
+ && ((formal->as->type != AS_ASSUMED_SHAPE && !formal->attr.pointer)
+ || formal->attr.contiguous))
+ {
+ if (where)
+ gfc_error ("Dummy argument '%s' has to be a pointer or assumed-shape "
+ "array without CONTIGUOUS attribute - as actual argument at"
+ " %L is not simply contiguous and both are ASYNCHRONOUS "
+ "or VOLATILE", formal->name, &actual->where);
+ return 0;
+ }
+
if (symbol_rank (formal) == actual->rank)
return 1;
rank_check = where != NULL && !is_elemental && formal->as
&& (formal->as->type == AS_ASSUMED_SHAPE
- || formal->as->type == AS_DEFERRED);
+ || formal->as->type == AS_DEFERRED)
+ && actual->expr_type != EXPR_NULL;
- if (rank_check || ranks_must_agree || formal->attr.pointer
+ /* Scalar & coindexed, see: F2008, Section 12.5.2.4. */
+ if (rank_check || ranks_must_agree
+ || (formal->attr.pointer && actual->expr_type != EXPR_NULL)
|| (actual->rank != 0 && !(is_elemental || formal->attr.dimension))
- || (actual->rank == 0 && formal->as->type == AS_ASSUMED_SHAPE))
+ || (actual->rank == 0 && formal->as->type == AS_ASSUMED_SHAPE
+ && actual->expr_type != EXPR_NULL)
+ || (actual->rank == 0 && formal->attr.dimension
+ && gfc_is_coindexed (actual)))
{
if (where)
- gfc_error ("Rank mismatch in argument '%s' at %L (%d and %d)",
- formal->name, &actual->where, symbol_rank (formal),
- actual->rank);
+ argument_rank_mismatch (formal->name, &actual->where,
+ symbol_rank (formal), actual->rank);
return 0;
}
else if (actual->rank != 0 && (is_elemental || formal->attr.dimension))
- (F2003) if the actual argument is of type character. */
for (ref = actual->ref; ref; ref = ref->next)
- if (ref->type == REF_ARRAY && ref->u.ar.type == AR_ELEMENT)
+ if (ref->type == REF_ARRAY && ref->u.ar.type == AR_ELEMENT
+ && ref->u.ar.dimen > 0)
break;
/* Not an array element. */
else
return 1;
}
- else if (ref == NULL)
+ else if (ref == NULL && actual->expr_type != EXPR_NULL)
{
if (where)
- gfc_error ("Rank mismatch in argument '%s' at %L (%d and %d)",
- formal->name, &actual->where, symbol_rank (formal),
- actual->rank);
+ argument_rank_mismatch (formal->name, &actual->where,
+ symbol_rank (formal), actual->rank);
return 0;
}
}
-/* Given a symbol of a formal argument list and an expression, see if
- the two are compatible as arguments. Returns nonzero if
- compatible, zero if not compatible. */
-
-static int
-compare_parameter_protected (gfc_symbol *formal, gfc_expr *actual)
-{
- if (actual->expr_type != EXPR_VARIABLE)
- return 1;
-
- if (!actual->symtree->n.sym->attr.is_protected)
- return 1;
-
- if (!actual->symtree->n.sym->attr.use_assoc)
- return 1;
-
- if (formal->attr.intent == INTENT_IN
- || formal->attr.intent == INTENT_UNKNOWN)
- return 1;
-
- if (!actual->symtree->n.sym->attr.pointer)
- return 0;
-
- if (actual->symtree->n.sym->attr.pointer && formal->attr.pointer)
- return 0;
-
- return 1;
-}
-
-
/* Returns the storage size of a symbol (formal argument) or
zero if it cannot be determined. */
if (sym->ts.type == BT_CHARACTER)
{
- if (sym->ts.cl && sym->ts.cl->length
- && sym->ts.cl->length->expr_type == EXPR_CONSTANT)
- strlen = mpz_get_ui (sym->ts.cl->length->value.integer);
+ if (sym->ts.u.cl && sym->ts.u.cl->length
+ && sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
+ strlen = mpz_get_ui (sym->ts.u.cl->length->value.integer);
else
return 0;
}
|| sym->as->lower[i]->expr_type != EXPR_CONSTANT)
return 0;
- elements *= mpz_get_ui (sym->as->upper[i]->value.integer)
- - mpz_get_ui (sym->as->lower[i]->value.integer) + 1L;
+ elements *= mpz_get_si (sym->as->upper[i]->value.integer)
+ - mpz_get_si (sym->as->lower[i]->value.integer) + 1L;
}
return strlen*elements;
if (e->ts.type == BT_CHARACTER)
{
- if (e->ts.cl && e->ts.cl->length
- && e->ts.cl->length->expr_type == EXPR_CONSTANT)
- strlen = mpz_get_si (e->ts.cl->length->value.integer);
+ if (e->ts.u.cl && e->ts.u.cl->length
+ && e->ts.u.cl->length->expr_type == EXPR_CONSTANT)
+ strlen = mpz_get_si (e->ts.u.cl->length->value.integer);
else if (e->expr_type == EXPR_CONSTANT
- && (e->ts.cl == NULL || e->ts.cl->length == NULL))
+ && (e->ts.u.cl == NULL || e->ts.u.cl->length == NULL))
strlen = e->value.character.length;
else
return 0;
which has a vector subscript. If it has, one is returned,
otherwise zero. */
-static int
-has_vector_subscript (gfc_expr *e)
+int
+gfc_has_vector_subscript (gfc_expr *e)
{
int i;
gfc_ref *ref;
for (f = formal; f; f = f->next)
n++;
- new_arg = (gfc_actual_arglist **) alloca (n * sizeof (gfc_actual_arglist *));
+ new_arg = XALLOCAVEC (gfc_actual_arglist *, n);
for (i = 0; i < n; i++)
new_arg[i] = NULL;
"call at %L", where);
return 0;
}
+
+ if (a->expr->expr_type == EXPR_NULL && !f->sym->attr.pointer
+ && (f->sym->attr.allocatable || !f->sym->attr.optional
+ || (gfc_option.allow_std & GFC_STD_F2008) == 0))
+ {
+ if (where && (f->sym->attr.allocatable || !f->sym->attr.optional))
+ gfc_error ("Unexpected NULL() intrinsic at %L to dummy '%s'",
+ where, f->sym->name);
+ else if (where)
+ gfc_error ("Fortran 2008: Null pointer at %L to non-pointer "
+ "dummy '%s'", where, f->sym->name);
+
+ return 0;
+ }
if (!compare_parameter (f->sym, a->expr, ranks_must_agree,
is_elemental, where))
and assumed-shape dummies, the string length needs to match
exactly. */
if (a->expr->ts.type == BT_CHARACTER
- && a->expr->ts.cl && a->expr->ts.cl->length
- && a->expr->ts.cl->length->expr_type == EXPR_CONSTANT
- && f->sym->ts.cl && f->sym->ts.cl && f->sym->ts.cl->length
- && f->sym->ts.cl->length->expr_type == EXPR_CONSTANT
+ && a->expr->ts.u.cl && a->expr->ts.u.cl->length
+ && a->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT
+ && f->sym->ts.u.cl && f->sym->ts.u.cl && f->sym->ts.u.cl->length
+ && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT
&& (f->sym->attr.pointer || f->sym->attr.allocatable
|| (f->sym->as && f->sym->as->type == AS_ASSUMED_SHAPE))
- && (mpz_cmp (a->expr->ts.cl->length->value.integer,
- f->sym->ts.cl->length->value.integer) != 0))
+ && (mpz_cmp (a->expr->ts.u.cl->length->value.integer,
+ f->sym->ts.u.cl->length->value.integer) != 0))
{
if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))
gfc_warning ("Character length mismatch (%ld/%ld) between actual "
"argument and pointer or allocatable dummy argument "
"'%s' at %L",
- mpz_get_si (a->expr->ts.cl->length->value.integer),
- mpz_get_si (f->sym->ts.cl->length->value.integer),
+ mpz_get_si (a->expr->ts.u.cl->length->value.integer),
+ mpz_get_si (f->sym->ts.u.cl->length->value.integer),
f->sym->name, &a->expr->where);
else if (where)
gfc_warning ("Character length mismatch (%ld/%ld) between actual "
"argument and assumed-shape dummy argument '%s' "
"at %L",
- mpz_get_si (a->expr->ts.cl->length->value.integer),
- mpz_get_si (f->sym->ts.cl->length->value.integer),
+ mpz_get_si (a->expr->ts.u.cl->length->value.integer),
+ mpz_get_si (f->sym->ts.u.cl->length->value.integer),
f->sym->name, &a->expr->where);
return 0;
}
}
if (a->expr->expr_type != EXPR_NULL
- && compare_allocatable (f->sym, a->expr) == 0)
+ && (gfc_option.allow_std & GFC_STD_F2008) == 0
+ && compare_pointer (f->sym, a->expr) == 2)
{
if (where)
- gfc_error ("Actual argument for '%s' must be ALLOCATABLE at %L",
- f->sym->name, &a->expr->where);
+ gfc_error ("Fortran 2008: Non-pointer actual argument at %L to "
+ "pointer dummy '%s'", &a->expr->where,f->sym->name);
return 0;
}
+
- /* Check intent = OUT/INOUT for definable actual argument. */
- if ((a->expr->expr_type != EXPR_VARIABLE
- || (a->expr->symtree->n.sym->attr.flavor != FL_VARIABLE
- && a->expr->symtree->n.sym->attr.flavor != FL_PROCEDURE))
- && (f->sym->attr.intent == INTENT_OUT
- || f->sym->attr.intent == INTENT_INOUT))
+ /* Fortran 2008, C1242. */
+ if (f->sym->attr.pointer && gfc_is_coindexed (a->expr))
{
if (where)
- gfc_error ("Actual argument at %L must be definable as "
- "the dummy argument '%s' is INTENT = OUT/INOUT",
+ gfc_error ("Coindexed actual argument at %L to pointer "
+ "dummy '%s'",
&a->expr->where, f->sym->name);
return 0;
}
- if (!compare_parameter_protected(f->sym, a->expr))
+ /* Fortran 2008, 12.5.2.5 (no constraint). */
+ if (a->expr->expr_type == EXPR_VARIABLE
+ && f->sym->attr.intent != INTENT_IN
+ && f->sym->attr.allocatable
+ && gfc_is_coindexed (a->expr))
{
if (where)
- gfc_error ("Actual argument at %L is use-associated with "
- "PROTECTED attribute and dummy argument '%s' is "
- "INTENT = OUT/INOUT",
- &a->expr->where,f->sym->name);
+ gfc_error ("Coindexed actual argument at %L to allocatable "
+ "dummy '%s' requires INTENT(IN)",
+ &a->expr->where, f->sym->name);
+ return 0;
+ }
+
+ /* Fortran 2008, C1237. */
+ if (a->expr->expr_type == EXPR_VARIABLE
+ && (f->sym->attr.asynchronous || f->sym->attr.volatile_)
+ && gfc_is_coindexed (a->expr)
+ && (a->expr->symtree->n.sym->attr.volatile_
+ || a->expr->symtree->n.sym->attr.asynchronous))
+ {
+ if (where)
+ gfc_error ("Coindexed ASYNCHRONOUS or VOLATILE actual argument at "
+ "at %L requires that dummy %s' has neither "
+ "ASYNCHRONOUS nor VOLATILE", &a->expr->where,
+ f->sym->name);
+ return 0;
+ }
+
+ /* Fortran 2008, 12.5.2.4 (no constraint). */
+ if (a->expr->expr_type == EXPR_VARIABLE
+ && f->sym->attr.intent != INTENT_IN && !f->sym->attr.value
+ && gfc_is_coindexed (a->expr)
+ && gfc_has_ultimate_allocatable (a->expr))
+ {
+ if (where)
+ gfc_error ("Coindexed actual argument at %L with allocatable "
+ "ultimate component to dummy '%s' requires either VALUE "
+ "or INTENT(IN)", &a->expr->where, f->sym->name);
+ return 0;
+ }
+
+ if (a->expr->expr_type != EXPR_NULL
+ && compare_allocatable (f->sym, a->expr) == 0)
+ {
+ if (where)
+ gfc_error ("Actual argument for '%s' must be ALLOCATABLE at %L",
+ f->sym->name, &a->expr->where);
return 0;
}
+ /* Check intent = OUT/INOUT for definable actual argument. */
+ if ((f->sym->attr.intent == INTENT_OUT
+ || f->sym->attr.intent == INTENT_INOUT))
+ {
+ const char* context = (where
+ ? _("actual argument to INTENT = OUT/INOUT")
+ : NULL);
+
+ if (f->sym->attr.pointer
+ && gfc_check_vardef_context (a->expr, true, context)
+ == FAILURE)
+ return 0;
+ if (gfc_check_vardef_context (a->expr, false, context)
+ == FAILURE)
+ return 0;
+ }
+
if ((f->sym->attr.intent == INTENT_OUT
|| f->sym->attr.intent == INTENT_INOUT
- || f->sym->attr.volatile_)
- && has_vector_subscript (a->expr))
+ || f->sym->attr.volatile_
+ || f->sym->attr.asynchronous)
+ && gfc_has_vector_subscript (a->expr))
{
if (where)
- gfc_error ("Array-section actual argument with vector subscripts "
- "at %L is incompatible with INTENT(OUT), INTENT(INOUT) "
- "or VOLATILE attribute of the dummy argument '%s'",
+ gfc_error ("Array-section actual argument with vector "
+ "subscripts at %L is incompatible with INTENT(OUT), "
+ "INTENT(INOUT), VOLATILE or ASYNCHRONOUS attribute "
+ "of the dummy argument '%s'",
&a->expr->where, f->sym->name);
return 0;
}
}
if (n == 0)
return t;
- p = (argpair *) alloca (n * sizeof (argpair));
+ p = XALLOCAVEC (argpair, n);
for (i = 0, f1 = f, a1 = a; i < n; i++, f1 = f1->next, a1 = a1->next)
{
return FAILURE;
}
}
+
+ /* Fortran 2008, C1283. */
+ if (gfc_pure (NULL) && gfc_is_coindexed (a->expr))
+ {
+ if (f_intent == INTENT_INOUT || f_intent == INTENT_OUT)
+ {
+ gfc_error ("Coindexed actual argument at %L in PURE procedure "
+ "is passed to an INTENT(%s) argument",
+ &a->expr->where, gfc_intent_string (f_intent));
+ return FAILURE;
+ }
+
+ if (f->sym->attr.pointer)
+ {
+ gfc_error ("Coindexed actual argument at %L in PURE procedure "
+ "is passed to a POINTER dummy argument",
+ &a->expr->where);
+ return FAILURE;
+ }
+ }
+
+ /* F2008, Section 12.5.2.4. */
+ if (a->expr->ts.type == BT_CLASS && f->sym->ts.type == BT_CLASS
+ && gfc_is_coindexed (a->expr))
+ {
+ gfc_error ("Coindexed polymorphic actual argument at %L is passed "
+ "polymorphic dummy argument '%s'",
+ &a->expr->where, f->sym->name);
+ return FAILURE;
+ }
}
return SUCCESS;
/* Warn about calls with an implicit interface. Special case
for calling a ISO_C_BINDING becase c_loc and c_funloc
- are pseudo-unknown. */
- if (gfc_option.warn_implicit_interface
- && sym->attr.if_source == IFSRC_UNKNOWN
- && ! sym->attr.is_iso_c)
- gfc_warning ("Procedure '%s' called with an implicit interface at %L",
- sym->name, where);
+ are pseudo-unknown. Additionally, warn about procedures not
+ explicitly declared at all if requested. */
+ if (sym->attr.if_source == IFSRC_UNKNOWN && ! sym->attr.is_iso_c)
+ {
+ if (gfc_option.warn_implicit_interface)
+ gfc_warning ("Procedure '%s' called with an implicit interface at %L",
+ sym->name, where);
+ else if (gfc_option.warn_implicit_procedure
+ && sym->attr.proc == PROC_UNKNOWN)
+ gfc_warning ("Procedure '%s' called at %L is not explicitly declared",
+ sym->name, where);
+ }
if (sym->attr.if_source == IFSRC_UNKNOWN)
{
}
+/* See if the arglist to an operator-call contains a derived-type argument
+ with a matching type-bound operator. If so, return the matching specific
+ procedure defined as operator-target as well as the base-object to use
+ (which is the found derived-type argument with operator). The generic
+ name, if any, is transmitted to the final expression via 'gname'. */
+
+static gfc_typebound_proc*
+matching_typebound_op (gfc_expr** tb_base,
+ gfc_actual_arglist* args,
+ gfc_intrinsic_op op, const char* uop,
+ const char ** gname)
+{
+ gfc_actual_arglist* base;
+
+ for (base = args; base; base = base->next)
+ if (base->expr->ts.type == BT_DERIVED || base->expr->ts.type == BT_CLASS)
+ {
+ gfc_typebound_proc* tb;
+ gfc_symbol* derived;
+ gfc_try result;
+
+ if (base->expr->ts.type == BT_CLASS)
+ derived = CLASS_DATA (base->expr)->ts.u.derived;
+ else
+ derived = base->expr->ts.u.derived;
+
+ if (op == INTRINSIC_USER)
+ {
+ gfc_symtree* tb_uop;
+
+ gcc_assert (uop);
+ tb_uop = gfc_find_typebound_user_op (derived, &result, uop,
+ false, NULL);
+
+ if (tb_uop)
+ tb = tb_uop->n.tb;
+ else
+ tb = NULL;
+ }
+ else
+ tb = gfc_find_typebound_intrinsic_op (derived, &result, op,
+ false, NULL);
+
+ /* This means we hit a PRIVATE operator which is use-associated and
+ should thus not be seen. */
+ if (result == FAILURE)
+ tb = NULL;
+
+ /* Look through the super-type hierarchy for a matching specific
+ binding. */
+ for (; tb; tb = tb->overridden)
+ {
+ gfc_tbp_generic* g;
+
+ gcc_assert (tb->is_generic);
+ for (g = tb->u.generic; g; g = g->next)
+ {
+ gfc_symbol* target;
+ gfc_actual_arglist* argcopy;
+ bool matches;
+
+ gcc_assert (g->specific);
+ if (g->specific->error)
+ continue;
+
+ target = g->specific->u.specific->n.sym;
+
+ /* Check if this arglist matches the formal. */
+ argcopy = gfc_copy_actual_arglist (args);
+ matches = gfc_arglist_matches_symbol (&argcopy, target);
+ gfc_free_actual_arglist (argcopy);
+
+ /* Return if we found a match. */
+ if (matches)
+ {
+ *tb_base = base->expr;
+ *gname = g->specific_st->name;
+ return g->specific;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* For the 'actual arglist' of an operator call and a specific typebound
+ procedure that has been found the target of a type-bound operator, build the
+ appropriate EXPR_COMPCALL and resolve it. We take this indirection over
+ type-bound procedures rather than resolving type-bound operators 'directly'
+ so that we can reuse the existing logic. */
+
+static void
+build_compcall_for_operator (gfc_expr* e, gfc_actual_arglist* actual,
+ gfc_expr* base, gfc_typebound_proc* target,
+ const char *gname)
+{
+ e->expr_type = EXPR_COMPCALL;
+ e->value.compcall.tbp = target;
+ e->value.compcall.name = gname ? gname : "$op";
+ e->value.compcall.actual = actual;
+ e->value.compcall.base_object = base;
+ e->value.compcall.ignore_pass = 1;
+ e->value.compcall.assign = 0;
+}
+
+
/* This subroutine is called when an expression is being resolved.
The expression node in question is either a user defined operator
or an intrinsic operator with arguments that aren't compatible
with the operator. This subroutine builds an actual argument list
corresponding to the operands, then searches for a compatible
interface. If one is found, the expression node is replaced with
- the appropriate function call. */
+ the appropriate function call.
+ real_error is an additional output argument that specifies if FAILURE
+ is because of some real error and not because no match was found. */
gfc_try
-gfc_extend_expr (gfc_expr *e)
+gfc_extend_expr (gfc_expr *e, bool *real_error)
{
gfc_actual_arglist *actual;
gfc_symbol *sym;
gfc_namespace *ns;
gfc_user_op *uop;
gfc_intrinsic_op i;
+ const char *gname;
sym = NULL;
actual = gfc_get_actual_arglist ();
actual->expr = e->value.op.op1;
+ *real_error = false;
+ gname = NULL;
+
if (e->value.op.op2 != NULL)
{
actual->next = gfc_get_actual_arglist ();
to check if either is defined. */
switch (i)
{
- case INTRINSIC_EQ:
- case INTRINSIC_EQ_OS:
- sym = gfc_search_interface (ns->op[INTRINSIC_EQ], 0, &actual);
- if (sym == NULL)
- sym = gfc_search_interface (ns->op[INTRINSIC_EQ_OS], 0, &actual);
- break;
-
- case INTRINSIC_NE:
- case INTRINSIC_NE_OS:
- sym = gfc_search_interface (ns->op[INTRINSIC_NE], 0, &actual);
- if (sym == NULL)
- sym = gfc_search_interface (ns->op[INTRINSIC_NE_OS], 0, &actual);
- break;
-
- case INTRINSIC_GT:
- case INTRINSIC_GT_OS:
- sym = gfc_search_interface (ns->op[INTRINSIC_GT], 0, &actual);
- if (sym == NULL)
- sym = gfc_search_interface (ns->op[INTRINSIC_GT_OS], 0, &actual);
- break;
-
- case INTRINSIC_GE:
- case INTRINSIC_GE_OS:
- sym = gfc_search_interface (ns->op[INTRINSIC_GE], 0, &actual);
- if (sym == NULL)
- sym = gfc_search_interface (ns->op[INTRINSIC_GE_OS], 0, &actual);
- break;
-
- case INTRINSIC_LT:
- case INTRINSIC_LT_OS:
- sym = gfc_search_interface (ns->op[INTRINSIC_LT], 0, &actual);
- if (sym == NULL)
- sym = gfc_search_interface (ns->op[INTRINSIC_LT_OS], 0, &actual);
- break;
-
- case INTRINSIC_LE:
- case INTRINSIC_LE_OS:
- sym = gfc_search_interface (ns->op[INTRINSIC_LE], 0, &actual);
- if (sym == NULL)
- sym = gfc_search_interface (ns->op[INTRINSIC_LE_OS], 0, &actual);
- break;
+#define CHECK_OS_COMPARISON(comp) \
+ case INTRINSIC_##comp: \
+ case INTRINSIC_##comp##_OS: \
+ sym = gfc_search_interface (ns->op[INTRINSIC_##comp], 0, &actual); \
+ if (!sym) \
+ sym = gfc_search_interface (ns->op[INTRINSIC_##comp##_OS], 0, &actual); \
+ break;
+ CHECK_OS_COMPARISON(EQ)
+ CHECK_OS_COMPARISON(NE)
+ CHECK_OS_COMPARISON(GT)
+ CHECK_OS_COMPARISON(GE)
+ CHECK_OS_COMPARISON(LT)
+ CHECK_OS_COMPARISON(LE)
+#undef CHECK_OS_COMPARISON
default:
sym = gfc_search_interface (ns->op[i], 0, &actual);
}
}
+ /* TODO: Do an ambiguity-check and error if multiple matching interfaces are
+ found rather than just taking the first one and not checking further. */
+
if (sym == NULL)
{
+ gfc_typebound_proc* tbo;
+ gfc_expr* tb_base;
+
+ /* See if we find a matching type-bound operator. */
+ if (i == INTRINSIC_USER)
+ tbo = matching_typebound_op (&tb_base, actual,
+ i, e->value.op.uop->name, &gname);
+ else
+ switch (i)
+ {
+#define CHECK_OS_COMPARISON(comp) \
+ case INTRINSIC_##comp: \
+ case INTRINSIC_##comp##_OS: \
+ tbo = matching_typebound_op (&tb_base, actual, \
+ INTRINSIC_##comp, NULL, &gname); \
+ if (!tbo) \
+ tbo = matching_typebound_op (&tb_base, actual, \
+ INTRINSIC_##comp##_OS, NULL, &gname); \
+ break;
+ CHECK_OS_COMPARISON(EQ)
+ CHECK_OS_COMPARISON(NE)
+ CHECK_OS_COMPARISON(GT)
+ CHECK_OS_COMPARISON(GE)
+ CHECK_OS_COMPARISON(LT)
+ CHECK_OS_COMPARISON(LE)
+#undef CHECK_OS_COMPARISON
+
+ default:
+ tbo = matching_typebound_op (&tb_base, actual, i, NULL, &gname);
+ break;
+ }
+
+ /* If there is a matching typebound-operator, replace the expression with
+ a call to it and succeed. */
+ if (tbo)
+ {
+ gfc_try result;
+
+ gcc_assert (tb_base);
+ build_compcall_for_operator (e, actual, tb_base, tbo, gname);
+
+ result = gfc_resolve_expr (e);
+ if (result == FAILURE)
+ *real_error = true;
+
+ return result;
+ }
+
/* Don't use gfc_free_actual_arglist(). */
if (actual->next != NULL)
gfc_free (actual->next);
e->value.function.name = NULL;
e->user_operator = 1;
- if (gfc_pure (NULL) && !gfc_pure (sym))
+ if (gfc_resolve_expr (e) == FAILURE)
{
- gfc_error ("Function '%s' called in lieu of an operator at %L must "
- "be PURE", sym->name, &e->where);
+ *real_error = true;
return FAILURE;
}
- if (gfc_resolve_expr (e) == FAILURE)
- return FAILURE;
-
return SUCCESS;
}
gfc_actual_arglist *actual;
gfc_expr *lhs, *rhs;
gfc_symbol *sym;
+ const char *gname;
+
+ gname = NULL;
lhs = c->expr1;
rhs = c->expr2;
/* Don't allow an intrinsic assignment to be replaced. */
- if (lhs->ts.type != BT_DERIVED
+ if (lhs->ts.type != BT_DERIVED && lhs->ts.type != BT_CLASS
&& (rhs->rank == 0 || rhs->rank == lhs->rank)
&& (lhs->ts.type == rhs->ts.type
|| (gfc_numeric_ts (&lhs->ts) && gfc_numeric_ts (&rhs->ts))))
break;
}
+ /* TODO: Ambiguity-check, see above for gfc_extend_expr. */
+
if (sym == NULL)
{
+ gfc_typebound_proc* tbo;
+ gfc_expr* tb_base;
+
+ /* See if we find a matching type-bound assignment. */
+ tbo = matching_typebound_op (&tb_base, actual,
+ INTRINSIC_ASSIGN, NULL, &gname);
+
+ /* If there is one, replace the expression with a call to it and
+ succeed. */
+ if (tbo)
+ {
+ gcc_assert (tb_base);
+ c->expr1 = gfc_get_expr ();
+ build_compcall_for_operator (c->expr1, actual, tb_base, tbo, gname);
+ c->expr1->value.compcall.assign = 1;
+ c->expr2 = NULL;
+ c->op = EXEC_COMPCALL;
+
+ /* c is resolved from the caller, so no need to do it here. */
+
+ return SUCCESS;
+ }
+
gfc_free (actual->next);
gfc_free (actual);
return FAILURE;