re PR fortran/37425 (Fortran 2003: GENERIC bindings as operators)
2009-08-10 Daniel Kraft <d@domob.eu> PR fortran/37425 * gfortran.dg/typebound_operator_1.f03: New test. * gfortran.dg/typebound_operator_2.f03: New test. 2009-08-10 Daniel Kraft <d@domob.eu> PR fortran/37425 * gfortran.h (struct gfc_namespace): New fields tb_uop_root and tb_op. (gfc_find_typebound_user_op): New routine. (gfc_find_typebound_intrinsic_op): Ditto. (gfc_check_operator_interface): Now public routine. * decl.c (gfc_match_generic): Match OPERATOR(X) or ASSIGNMENT(=). * interface.c (check_operator_interface): Made public, renamed to `gfc_check_operator_interface' accordingly and hand in the interface as gfc_symbol rather than gfc_interface so it is useful for type-bound operators, too. Return boolean result. (gfc_check_interfaces): Adapt call to `check_operator_interface'. * symbol.c (gfc_get_namespace): Initialize new field `tb_op'. (gfc_free_namespace): Free `tb_uop_root'-based tree. (find_typebound_proc_uop): New helper function. (gfc_find_typebound_proc): Use it. (gfc_find_typebound_user_op): New method. (gfc_find_typebound_intrinsic_op): Ditto. * resolve.c (resolve_tb_generic_targets): New helper function. (resolve_typebound_generic): Use it. (resolve_typebound_intrinsic_op), (resolve_typebound_user_op): New. (resolve_typebound_procedures): Resolve operators, too. (check_uop_procedure): New, code from gfc_resolve_uops. (gfc_resolve_uops): Moved main code to new `check_uop_procedure'. From-SVN: r150622
This commit is contained in:
parent
4f4e722eb6
commit
94747289e9
9 changed files with 666 additions and 160 deletions
|
@ -1,3 +1,29 @@
|
|||
2009-08-10 Daniel Kraft <d@domob.eu>
|
||||
|
||||
PR fortran/37425
|
||||
* gfortran.h (struct gfc_namespace): New fields tb_uop_root and tb_op.
|
||||
(gfc_find_typebound_user_op): New routine.
|
||||
(gfc_find_typebound_intrinsic_op): Ditto.
|
||||
(gfc_check_operator_interface): Now public routine.
|
||||
* decl.c (gfc_match_generic): Match OPERATOR(X) or ASSIGNMENT(=).
|
||||
* interface.c (check_operator_interface): Made public, renamed to
|
||||
`gfc_check_operator_interface' accordingly and hand in the interface
|
||||
as gfc_symbol rather than gfc_interface so it is useful for type-bound
|
||||
operators, too. Return boolean result.
|
||||
(gfc_check_interfaces): Adapt call to `check_operator_interface'.
|
||||
* symbol.c (gfc_get_namespace): Initialize new field `tb_op'.
|
||||
(gfc_free_namespace): Free `tb_uop_root'-based tree.
|
||||
(find_typebound_proc_uop): New helper function.
|
||||
(gfc_find_typebound_proc): Use it.
|
||||
(gfc_find_typebound_user_op): New method.
|
||||
(gfc_find_typebound_intrinsic_op): Ditto.
|
||||
* resolve.c (resolve_tb_generic_targets): New helper function.
|
||||
(resolve_typebound_generic): Use it.
|
||||
(resolve_typebound_intrinsic_op), (resolve_typebound_user_op): New.
|
||||
(resolve_typebound_procedures): Resolve operators, too.
|
||||
(check_uop_procedure): New, code from gfc_resolve_uops.
|
||||
(gfc_resolve_uops): Moved main code to new `check_uop_procedure'.
|
||||
|
||||
2009-08-10 Janus Weil <janus@gcc.gnu.org>
|
||||
|
||||
PR fortran/40940
|
||||
|
|
|
@ -7406,11 +7406,13 @@ match
|
|||
gfc_match_generic (void)
|
||||
{
|
||||
char name[GFC_MAX_SYMBOL_LEN + 1];
|
||||
char bind_name[GFC_MAX_SYMBOL_LEN + 16]; /* Allow space for OPERATOR(...). */
|
||||
gfc_symbol* block;
|
||||
gfc_typebound_proc tbattr; /* Used for match_binding_attributes. */
|
||||
gfc_typebound_proc* tb;
|
||||
gfc_symtree* st;
|
||||
gfc_namespace* ns;
|
||||
interface_type op_type;
|
||||
gfc_intrinsic_op op;
|
||||
match m;
|
||||
|
||||
/* Check current state. */
|
||||
|
@ -7437,49 +7439,126 @@ gfc_match_generic (void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* The binding name and =>. */
|
||||
m = gfc_match (" %n =>", name);
|
||||
/* Match the binding name; depending on type (operator / generic) format
|
||||
it for future error messages into bind_name. */
|
||||
|
||||
m = gfc_match_generic_spec (&op_type, name, &op);
|
||||
if (m == MATCH_ERROR)
|
||||
return MATCH_ERROR;
|
||||
if (m == MATCH_NO)
|
||||
{
|
||||
gfc_error ("Expected generic name at %C");
|
||||
gfc_error ("Expected generic name or operator descriptor at %C");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If there's already something with this name, check that it is another
|
||||
GENERIC and then extend that rather than build a new node. */
|
||||
st = gfc_find_symtree (ns->tb_sym_root, name);
|
||||
if (st)
|
||||
switch (op_type)
|
||||
{
|
||||
gcc_assert (st->n.tb);
|
||||
tb = st->n.tb;
|
||||
case INTERFACE_GENERIC:
|
||||
snprintf (bind_name, sizeof (bind_name), "%s", name);
|
||||
break;
|
||||
|
||||
case INTERFACE_USER_OP:
|
||||
snprintf (bind_name, sizeof (bind_name), "OPERATOR(.%s.)", name);
|
||||
break;
|
||||
|
||||
case INTERFACE_INTRINSIC_OP:
|
||||
snprintf (bind_name, sizeof (bind_name), "OPERATOR(%s)",
|
||||
gfc_op2string (op));
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Match the required =>. */
|
||||
if (gfc_match (" =>") != MATCH_YES)
|
||||
{
|
||||
gfc_error ("Expected '=>' at %C");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Try to find existing GENERIC binding with this name / for this operator;
|
||||
if there is something, check that it is another GENERIC and then extend
|
||||
it rather than building a new node. Otherwise, create it and put it
|
||||
at the right position. */
|
||||
|
||||
switch (op_type)
|
||||
{
|
||||
case INTERFACE_USER_OP:
|
||||
case INTERFACE_GENERIC:
|
||||
{
|
||||
const bool is_op = (op_type == INTERFACE_USER_OP);
|
||||
gfc_symtree* st;
|
||||
|
||||
st = gfc_find_symtree (is_op ? ns->tb_uop_root : ns->tb_sym_root, name);
|
||||
if (st)
|
||||
{
|
||||
tb = st->n.tb;
|
||||
gcc_assert (tb);
|
||||
}
|
||||
else
|
||||
tb = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case INTERFACE_INTRINSIC_OP:
|
||||
tb = ns->tb_op[op];
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
if (tb)
|
||||
{
|
||||
if (!tb->is_generic)
|
||||
{
|
||||
gcc_assert (op_type == INTERFACE_GENERIC);
|
||||
gfc_error ("There's already a non-generic procedure with binding name"
|
||||
" '%s' for the derived type '%s' at %C",
|
||||
name, block->name);
|
||||
bind_name, block->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (tb->access != tbattr.access)
|
||||
{
|
||||
gfc_error ("Binding at %C must have the same access as already"
|
||||
" defined binding '%s'", name);
|
||||
" defined binding '%s'", bind_name);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
st = gfc_new_symtree (&ns->tb_sym_root, name);
|
||||
gcc_assert (st);
|
||||
|
||||
st->n.tb = tb = gfc_get_typebound_proc ();
|
||||
tb = gfc_get_typebound_proc ();
|
||||
tb->where = gfc_current_locus;
|
||||
tb->access = tbattr.access;
|
||||
tb->is_generic = 1;
|
||||
tb->u.generic = NULL;
|
||||
|
||||
switch (op_type)
|
||||
{
|
||||
case INTERFACE_GENERIC:
|
||||
case INTERFACE_USER_OP:
|
||||
{
|
||||
const bool is_op = (op_type == INTERFACE_USER_OP);
|
||||
gfc_symtree* st;
|
||||
|
||||
st = gfc_new_symtree (is_op ? &ns->tb_uop_root : &ns->tb_sym_root,
|
||||
name);
|
||||
gcc_assert (st);
|
||||
st->n.tb = tb;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case INTERFACE_INTRINSIC_OP:
|
||||
ns->tb_op[op] = tb;
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, match all following names as specific targets. */
|
||||
|
@ -7504,7 +7583,7 @@ gfc_match_generic (void)
|
|||
if (target_st == target->specific_st)
|
||||
{
|
||||
gfc_error ("'%s' already defined as specific binding for the"
|
||||
" generic '%s' at %C", name, st->name);
|
||||
" generic '%s' at %C", name, bind_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
@ -1287,6 +1287,10 @@ typedef struct gfc_namespace
|
|||
|
||||
/* Tree containing type-bound procedures. */
|
||||
gfc_symtree *tb_sym_root;
|
||||
/* Type-bound user operators. */
|
||||
gfc_symtree *tb_uop_root;
|
||||
/* For derived-types, store type-bound intrinsic operators here. */
|
||||
gfc_typebound_proc *tb_op[GFC_INTRINSIC_OPS];
|
||||
/* Linked list of finalizer procedures. */
|
||||
struct gfc_finalizer *finalizers;
|
||||
|
||||
|
@ -2448,6 +2452,10 @@ gfc_gsymbol *gfc_find_gsymbol (gfc_gsymbol *, const char *);
|
|||
gfc_typebound_proc* gfc_get_typebound_proc (void);
|
||||
gfc_symbol* gfc_get_derived_super_type (gfc_symbol*);
|
||||
gfc_symtree* gfc_find_typebound_proc (gfc_symbol*, gfc_try*, const char*, bool);
|
||||
gfc_symtree* gfc_find_typebound_user_op (gfc_symbol*, gfc_try*,
|
||||
const char*, bool);
|
||||
gfc_typebound_proc* gfc_find_typebound_intrinsic_op (gfc_symbol*, gfc_try*,
|
||||
gfc_intrinsic_op, bool);
|
||||
gfc_symtree* gfc_get_tbp_symtree (gfc_symtree**, const char*);
|
||||
|
||||
void gfc_copy_formal_args (gfc_symbol *, gfc_symbol *);
|
||||
|
@ -2636,6 +2644,7 @@ gfc_interface *gfc_current_interface_head (void);
|
|||
void gfc_set_current_interface_head (gfc_interface *);
|
||||
gfc_symtree* gfc_find_sym_in_symtree (gfc_symbol*);
|
||||
bool gfc_arglist_matches_symbol (gfc_actual_arglist**, gfc_symbol*);
|
||||
bool gfc_check_operator_interface (gfc_symbol*, gfc_intrinsic_op, locus);
|
||||
|
||||
/* io.c */
|
||||
extern gfc_st_label format_asterisk;
|
||||
|
|
|
@ -544,17 +544,16 @@ find_keyword_arg (const char *name, gfc_formal_arglist *f)
|
|||
/* 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;
|
||||
|
@ -562,34 +561,32 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
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
|
||||
|
@ -598,8 +595,8 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
|| (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
|
||||
|
@ -609,20 +606,20 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
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
|
||||
&& (r1 == 0 || r1 == r2)
|
||||
&& (sym->formal->sym->ts.type == sym->formal->next->sym->ts.type
|
||||
|
@ -630,8 +627,8 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
&& 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
|
||||
|
@ -639,8 +636,8 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,22 +645,34 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
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
|
||||
|
@ -686,7 +695,7 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
if (t1 == BT_LOGICAL)
|
||||
goto bad_repl;
|
||||
else
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args == 1 && (op == INTRINSIC_PLUS || op == INTRINSIC_MINUS))
|
||||
|
@ -694,20 +703,20 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op op)
|
|||
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)
|
||||
{
|
||||
|
@ -760,14 +769,14 @@ check_operator_interface (gfc_interface *intr, gfc_intrinsic_op 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1229,7 +1238,9 @@ gfc_check_interfaces (gfc_namespace *ns)
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -8793,37 +8793,27 @@ check_generic_tbp_ambiguity (gfc_tbp_generic* t1, gfc_tbp_generic* t2,
|
|||
}
|
||||
|
||||
|
||||
/* Resolve a GENERIC procedure binding for a derived type. */
|
||||
/* 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 gfc_try
|
||||
resolve_typebound_generic (gfc_symbol* derived, gfc_symtree* st)
|
||||
resolve_tb_generic_targets (gfc_symbol* super_type,
|
||||
gfc_typebound_proc* p, const char* name)
|
||||
{
|
||||
gfc_tbp_generic* target;
|
||||
gfc_symtree* first_target;
|
||||
gfc_symbol* super_type;
|
||||
gfc_symtree* inherited;
|
||||
locus where;
|
||||
|
||||
gcc_assert (st->n.tb);
|
||||
gcc_assert (st->n.tb->is_generic);
|
||||
|
||||
where = st->n.tb->where;
|
||||
super_type = gfc_get_derived_super_type (derived);
|
||||
|
||||
/* Find the overridden binding if any. */
|
||||
st->n.tb->overridden = NULL;
|
||||
if (super_type)
|
||||
{
|
||||
gfc_symtree* overridden;
|
||||
overridden = gfc_find_typebound_proc (super_type, NULL, st->name, true);
|
||||
|
||||
if (overridden && overridden->n.tb)
|
||||
st->n.tb->overridden = overridden->n.tb;
|
||||
}
|
||||
gcc_assert (p && p->is_generic);
|
||||
|
||||
/* Try to find the specific bindings for the symtrees in our target-list. */
|
||||
gcc_assert (st->n.tb->u.generic);
|
||||
for (target = st->n.tb->u.generic; target; target = target->next)
|
||||
gcc_assert (p->u.generic);
|
||||
for (target = p->u.generic; target; target = target->next)
|
||||
if (!target->specific)
|
||||
{
|
||||
gfc_typebound_proc* overridden_tbp;
|
||||
|
@ -8854,7 +8844,7 @@ resolve_typebound_generic (gfc_symbol* derived, gfc_symtree* st)
|
|||
}
|
||||
|
||||
gfc_error ("Undefined specific binding '%s' as target of GENERIC '%s'"
|
||||
" at %L", target_name, st->name, &where);
|
||||
" at %L", target_name, name, &p->where);
|
||||
return FAILURE;
|
||||
|
||||
/* Once we've found the specific binding, check it is not ambiguous with
|
||||
|
@ -8866,19 +8856,19 @@ specific_found:
|
|||
if (target->specific->is_generic)
|
||||
{
|
||||
gfc_error ("GENERIC '%s' at %L must target a specific binding,"
|
||||
" '%s' is GENERIC, too", st->name, &where, target_name);
|
||||
" '%s' is GENERIC, too", name, &p->where, target_name);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/* Check those already resolved on this type directly. */
|
||||
for (g = st->n.tb->u.generic; g; g = g->next)
|
||||
for (g = p->u.generic; g; g = g->next)
|
||||
if (g != target && g->specific
|
||||
&& check_generic_tbp_ambiguity (target, g, st->name, where)
|
||||
&& check_generic_tbp_ambiguity (target, g, name, p->where)
|
||||
== FAILURE)
|
||||
return FAILURE;
|
||||
|
||||
/* Check for ambiguity with inherited specific targets. */
|
||||
for (overridden_tbp = st->n.tb->overridden; overridden_tbp;
|
||||
for (overridden_tbp = p->overridden; overridden_tbp;
|
||||
overridden_tbp = overridden_tbp->overridden)
|
||||
if (overridden_tbp->is_generic)
|
||||
{
|
||||
|
@ -8886,36 +8876,167 @@ specific_found:
|
|||
{
|
||||
gcc_assert (g->specific);
|
||||
if (check_generic_tbp_ambiguity (target, g,
|
||||
st->name, where) == FAILURE)
|
||||
name, p->where) == FAILURE)
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we attempt to "overwrite" a specific binding, this is an error. */
|
||||
if (st->n.tb->overridden && !st->n.tb->overridden->is_generic)
|
||||
if (p->overridden && !p->overridden->is_generic)
|
||||
{
|
||||
gfc_error ("GENERIC '%s' at %L can't overwrite specific binding with"
|
||||
" the same name", st->name, &where);
|
||||
" the same name", name, &p->where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/* Take the SUBROUTINE/FUNCTION attributes of the first specific target, as
|
||||
all must have the same attributes here. */
|
||||
first_target = st->n.tb->u.generic->specific->u.specific;
|
||||
first_target = p->u.generic->specific->u.specific;
|
||||
gcc_assert (first_target);
|
||||
st->n.tb->subroutine = first_target->n.sym->attr.subroutine;
|
||||
st->n.tb->function = first_target->n.sym->attr.function;
|
||||
p->subroutine = first_target->n.sym->attr.subroutine;
|
||||
p->function = first_target->n.sym->attr.function;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Resolve the type-bound procedures for a derived type. */
|
||||
/* Resolve a GENERIC procedure binding for a derived type. */
|
||||
|
||||
static gfc_try
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* Resolve a type-bound intrinsic operator. */
|
||||
|
||||
static gfc_try
|
||||
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 SUCCESS;
|
||||
|
||||
/* 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);
|
||||
else
|
||||
p->overridden = NULL;
|
||||
|
||||
/* Resolve general GENERIC properties using worker function. */
|
||||
if (resolve_tb_generic_targets (super_type, p, gfc_op2string (op)) == FAILURE)
|
||||
goto error;
|
||||
|
||||
/* Check the targets to be procedures of correct interface. */
|
||||
for (target = p->u.generic; target; target = target->next)
|
||||
{
|
||||
gfc_symbol* target_proc;
|
||||
|
||||
gcc_assert (target->specific && !target->specific->is_generic);
|
||||
target_proc = target->specific->u.specific->n.sym;
|
||||
gcc_assert (target_proc);
|
||||
|
||||
if (!gfc_check_operator_interface (target_proc, op, p->where))
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
||||
error:
|
||||
p->error = 1;
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/* Resolve a type-bound user operator (tree-walker callback). */
|
||||
|
||||
static gfc_symbol* resolve_bindings_derived;
|
||||
static gfc_try resolve_bindings_result;
|
||||
|
||||
static gfc_try 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);
|
||||
|
||||
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)
|
||||
== FAILURE)
|
||||
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;
|
||||
|
||||
gcc_assert (target->specific && !target->specific->is_generic);
|
||||
target_proc = target->specific->u.specific->n.sym;
|
||||
gcc_assert (target_proc);
|
||||
|
||||
if (check_uop_procedure (target_proc, stree->n.tb->where) == FAILURE)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
resolve_bindings_result = FAILURE;
|
||||
stree->n.tb->error = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Resolve the type-bound procedures for a derived type. */
|
||||
|
||||
static void
|
||||
resolve_typebound_procedure (gfc_symtree* stree)
|
||||
{
|
||||
|
@ -9082,13 +9203,42 @@ error:
|
|||
static gfc_try
|
||||
resolve_typebound_procedures (gfc_symbol* derived)
|
||||
{
|
||||
int op;
|
||||
bool found_op;
|
||||
|
||||
if (!derived->f2k_derived || !derived->f2k_derived->tb_sym_root)
|
||||
return SUCCESS;
|
||||
|
||||
resolve_bindings_derived = derived;
|
||||
resolve_bindings_result = SUCCESS;
|
||||
gfc_traverse_symtree (derived->f2k_derived->tb_sym_root,
|
||||
&resolve_typebound_procedure);
|
||||
|
||||
if (derived->f2k_derived->tb_sym_root)
|
||||
gfc_traverse_symtree (derived->f2k_derived->tb_sym_root,
|
||||
&resolve_typebound_procedure);
|
||||
|
||||
found_op = (derived->f2k_derived->tb_uop_root != NULL);
|
||||
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) == FAILURE)
|
||||
resolve_bindings_result = FAILURE;
|
||||
if (p)
|
||||
found_op = true;
|
||||
}
|
||||
|
||||
/* FIXME: Remove this (and found_op) once calls are fully implemented. */
|
||||
if (found_op)
|
||||
{
|
||||
gfc_error ("Derived type '%s' at %L contains type-bound OPERATOR's,"
|
||||
" they are not yet implemented.",
|
||||
derived->name, &derived->declared_at);
|
||||
resolve_bindings_result = FAILURE;
|
||||
}
|
||||
|
||||
return resolve_bindings_result;
|
||||
}
|
||||
|
@ -11063,14 +11213,85 @@ resolve_fntype (gfc_namespace *ns)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* 12.3.2.1.1 Defined operators. */
|
||||
|
||||
static gfc_try
|
||||
check_uop_procedure (gfc_symbol *sym, locus where)
|
||||
{
|
||||
gfc_formal_arglist *formal;
|
||||
|
||||
if (!sym->attr.function)
|
||||
{
|
||||
gfc_error ("User operator procedure '%s' at %L must be a FUNCTION",
|
||||
sym->name, &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (sym->ts.type == BT_CHARACTER
|
||||
&& !(sym->ts.cl && sym->ts.cl->length)
|
||||
&& !(sym->result && sym->result->ts.cl
|
||||
&& sym->result->ts.cl->length))
|
||||
{
|
||||
gfc_error ("User operator procedure '%s' at %L cannot be assumed "
|
||||
"character length", sym->name, &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
formal = sym->formal;
|
||||
if (!formal || !formal->sym)
|
||||
{
|
||||
gfc_error ("User operator procedure '%s' at %L must have at least "
|
||||
"one argument", sym->name, &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (formal->sym->attr.intent != INTENT_IN)
|
||||
{
|
||||
gfc_error ("First argument of operator interface at %L must be "
|
||||
"INTENT(IN)", &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (formal->sym->attr.optional)
|
||||
{
|
||||
gfc_error ("First argument of operator interface at %L cannot be "
|
||||
"optional", &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
formal = formal->next;
|
||||
if (!formal || !formal->sym)
|
||||
return SUCCESS;
|
||||
|
||||
if (formal->sym->attr.intent != INTENT_IN)
|
||||
{
|
||||
gfc_error ("Second argument of operator interface at %L must be "
|
||||
"INTENT(IN)", &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (formal->sym->attr.optional)
|
||||
{
|
||||
gfc_error ("Second argument of operator interface at %L cannot be "
|
||||
"optional", &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (formal->next)
|
||||
{
|
||||
gfc_error ("Operator interface at %L must have, at most, two "
|
||||
"arguments", &where);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
gfc_resolve_uops (gfc_symtree *symtree)
|
||||
{
|
||||
gfc_interface *itr;
|
||||
gfc_symbol *sym;
|
||||
gfc_formal_arglist *formal;
|
||||
|
||||
if (symtree == NULL)
|
||||
return;
|
||||
|
@ -11079,51 +11300,7 @@ gfc_resolve_uops (gfc_symtree *symtree)
|
|||
gfc_resolve_uops (symtree->right);
|
||||
|
||||
for (itr = symtree->n.uop->op; itr; itr = itr->next)
|
||||
{
|
||||
sym = itr->sym;
|
||||
if (!sym->attr.function)
|
||||
gfc_error ("User operator procedure '%s' at %L must be a FUNCTION",
|
||||
sym->name, &sym->declared_at);
|
||||
|
||||
if (sym->ts.type == BT_CHARACTER
|
||||
&& !(sym->ts.cl && sym->ts.cl->length)
|
||||
&& !(sym->result && sym->result->ts.cl
|
||||
&& sym->result->ts.cl->length))
|
||||
gfc_error ("User operator procedure '%s' at %L cannot be assumed "
|
||||
"character length", sym->name, &sym->declared_at);
|
||||
|
||||
formal = sym->formal;
|
||||
if (!formal || !formal->sym)
|
||||
{
|
||||
gfc_error ("User operator procedure '%s' at %L must have at least "
|
||||
"one argument", sym->name, &sym->declared_at);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (formal->sym->attr.intent != INTENT_IN)
|
||||
gfc_error ("First argument of operator interface at %L must be "
|
||||
"INTENT(IN)", &sym->declared_at);
|
||||
|
||||
if (formal->sym->attr.optional)
|
||||
gfc_error ("First argument of operator interface at %L cannot be "
|
||||
"optional", &sym->declared_at);
|
||||
|
||||
formal = formal->next;
|
||||
if (!formal || !formal->sym)
|
||||
continue;
|
||||
|
||||
if (formal->sym->attr.intent != INTENT_IN)
|
||||
gfc_error ("Second argument of operator interface at %L must be "
|
||||
"INTENT(IN)", &sym->declared_at);
|
||||
|
||||
if (formal->sym->attr.optional)
|
||||
gfc_error ("Second argument of operator interface at %L cannot be "
|
||||
"optional", &sym->declared_at);
|
||||
|
||||
if (formal->next)
|
||||
gfc_error ("Operator interface at %L must have, at most, two "
|
||||
"arguments", &sym->declared_at);
|
||||
}
|
||||
check_uop_procedure (itr->sym, itr->sym->declared_at);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2220,7 +2220,10 @@ gfc_get_namespace (gfc_namespace *parent, int parent_types)
|
|||
ns->parent = parent;
|
||||
|
||||
for (in = GFC_INTRINSIC_BEGIN; in != GFC_INTRINSIC_END; in++)
|
||||
ns->operator_access[in] = ACCESS_UNKNOWN;
|
||||
{
|
||||
ns->operator_access[in] = ACCESS_UNKNOWN;
|
||||
ns->tb_op[in] = NULL;
|
||||
}
|
||||
|
||||
/* Initialize default implicit types. */
|
||||
for (i = 'a'; i <= 'z'; i++)
|
||||
|
@ -2948,7 +2951,6 @@ free_common_tree (gfc_symtree * common_tree)
|
|||
static void
|
||||
free_uop_tree (gfc_symtree *uop_tree)
|
||||
{
|
||||
|
||||
if (uop_tree == NULL)
|
||||
return;
|
||||
|
||||
|
@ -2956,7 +2958,6 @@ free_uop_tree (gfc_symtree *uop_tree)
|
|||
free_uop_tree (uop_tree->right);
|
||||
|
||||
gfc_free_interface (uop_tree->n.uop->op);
|
||||
|
||||
gfc_free (uop_tree->n.uop);
|
||||
gfc_free (uop_tree);
|
||||
}
|
||||
|
@ -3128,6 +3129,7 @@ gfc_free_namespace (gfc_namespace *ns)
|
|||
free_uop_tree (ns->uop_root);
|
||||
free_common_tree (ns->common_root);
|
||||
free_tb_tree (ns->tb_sym_root);
|
||||
free_tb_tree (ns->tb_uop_root);
|
||||
gfc_free_finalizer_list (ns->finalizers);
|
||||
gfc_free_charlen (ns->cl_list, NULL);
|
||||
free_st_labels (ns->st_labels);
|
||||
|
@ -4519,22 +4521,27 @@ gfc_get_derived_super_type (gfc_symbol* derived)
|
|||
}
|
||||
|
||||
|
||||
/* Find a type-bound procedure by name for a derived-type (looking recursively
|
||||
through the super-types). */
|
||||
/* General worker function to find either a type-bound procedure or a
|
||||
type-bound user operator. */
|
||||
|
||||
gfc_symtree*
|
||||
gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
|
||||
const char* name, bool noaccess)
|
||||
static gfc_symtree*
|
||||
find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
|
||||
const char* name, bool noaccess, bool uop)
|
||||
{
|
||||
gfc_symtree* res;
|
||||
gfc_symtree* root;
|
||||
|
||||
/* Set correct symbol-root. */
|
||||
gcc_assert (derived->f2k_derived);
|
||||
root = (uop ? derived->f2k_derived->tb_uop_root
|
||||
: derived->f2k_derived->tb_sym_root);
|
||||
|
||||
/* Set default to failure. */
|
||||
if (t)
|
||||
*t = FAILURE;
|
||||
|
||||
/* Try to find it in the current type's namespace. */
|
||||
gcc_assert (derived->f2k_derived);
|
||||
res = gfc_find_symtree (derived->f2k_derived->tb_sym_root, name);
|
||||
res = gfc_find_symtree (root, name);
|
||||
if (res && res->n.tb)
|
||||
{
|
||||
/* We found one. */
|
||||
|
@ -4558,7 +4565,79 @@ gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
|
|||
gfc_symbol* super_type;
|
||||
super_type = gfc_get_derived_super_type (derived);
|
||||
gcc_assert (super_type);
|
||||
return gfc_find_typebound_proc (super_type, t, name, noaccess);
|
||||
|
||||
return find_typebound_proc_uop (super_type, t, name, noaccess, uop);
|
||||
}
|
||||
|
||||
/* Nothing found. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Find a type-bound procedure or user operator by name for a derived-type
|
||||
(looking recursively through the super-types). */
|
||||
|
||||
gfc_symtree*
|
||||
gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
|
||||
const char* name, bool noaccess)
|
||||
{
|
||||
return find_typebound_proc_uop (derived, t, name, noaccess, false);
|
||||
}
|
||||
|
||||
gfc_symtree*
|
||||
gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t,
|
||||
const char* name, bool noaccess)
|
||||
{
|
||||
return find_typebound_proc_uop (derived, t, name, noaccess, true);
|
||||
}
|
||||
|
||||
|
||||
/* Find a type-bound intrinsic operator looking recursively through the
|
||||
super-type hierarchy. */
|
||||
|
||||
gfc_typebound_proc*
|
||||
gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
|
||||
gfc_intrinsic_op op, bool noaccess)
|
||||
{
|
||||
gfc_typebound_proc* res;
|
||||
|
||||
/* Set default to failure. */
|
||||
if (t)
|
||||
*t = FAILURE;
|
||||
|
||||
/* Try to find it in the current type's namespace. */
|
||||
if (derived->f2k_derived)
|
||||
res = derived->f2k_derived->tb_op[op];
|
||||
else
|
||||
res = NULL;
|
||||
|
||||
/* Check access. */
|
||||
if (res)
|
||||
{
|
||||
/* We found one. */
|
||||
if (t)
|
||||
*t = SUCCESS;
|
||||
|
||||
if (!noaccess && derived->attr.use_assoc
|
||||
&& res->access == ACCESS_PRIVATE)
|
||||
{
|
||||
gfc_error ("'%s' of '%s' is PRIVATE at %C",
|
||||
gfc_op2string (op), derived->name);
|
||||
if (t)
|
||||
*t = FAILURE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Otherwise, recurse on parent type if derived is an extension. */
|
||||
if (derived->attr.extension)
|
||||
{
|
||||
gfc_symbol* super_type;
|
||||
super_type = gfc_get_derived_super_type (derived);
|
||||
gcc_assert (super_type);
|
||||
|
||||
return gfc_find_typebound_intrinsic_op (super_type, t, op, noaccess);
|
||||
}
|
||||
|
||||
/* Nothing found. */
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2009-08-10 Daniel Kraft <d@domob.eu>
|
||||
|
||||
PR fortran/37425
|
||||
* gfortran.dg/typebound_operator_1.f03: New test.
|
||||
* gfortran.dg/typebound_operator_2.f03: New test.
|
||||
|
||||
2009-08-10 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/41006
|
||||
|
|
50
gcc/testsuite/gfortran.dg/typebound_operator_1.f03
Normal file
50
gcc/testsuite/gfortran.dg/typebound_operator_1.f03
Normal file
|
@ -0,0 +1,50 @@
|
|||
! { dg-do compile }
|
||||
! { dg-options "-w" }
|
||||
! FIXME: Remove -w once CLASS is fully supported.
|
||||
|
||||
! Type-bound procedures
|
||||
! Check correct type-bound operator definitions.
|
||||
|
||||
MODULE m
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE t ! { dg-error "not yet implemented" }
|
||||
CONTAINS
|
||||
PROCEDURE, PASS :: onearg
|
||||
PROCEDURE, PASS :: twoarg1
|
||||
PROCEDURE, PASS :: twoarg2
|
||||
PROCEDURE, PASS(me) :: assign_proc
|
||||
|
||||
GENERIC :: OPERATOR(.BINARY.) => twoarg1, twoarg2
|
||||
GENERIC :: OPERATOR(.UNARY.) => onearg
|
||||
GENERIC :: ASSIGNMENT(=) => assign_proc
|
||||
END TYPE t
|
||||
|
||||
CONTAINS
|
||||
|
||||
INTEGER FUNCTION onearg (me)
|
||||
CLASS(t), INTENT(IN) :: me
|
||||
onearg = 5
|
||||
END FUNCTION onearg
|
||||
|
||||
INTEGER FUNCTION twoarg1 (me, a)
|
||||
CLASS(t), INTENT(IN) :: me
|
||||
INTEGER, INTENT(IN) :: a
|
||||
twoarg1 = 42
|
||||
END FUNCTION twoarg1
|
||||
|
||||
INTEGER FUNCTION twoarg2 (me, a)
|
||||
CLASS(t), INTENT(IN) :: me
|
||||
REAL, INTENT(IN) :: a
|
||||
twoarg2 = 123
|
||||
END FUNCTION twoarg2
|
||||
|
||||
SUBROUTINE assign_proc (me, b)
|
||||
CLASS(t), INTENT(OUT) :: me
|
||||
CLASS(t), INTENT(IN) :: b
|
||||
me = t ()
|
||||
END SUBROUTINE assign_proc
|
||||
|
||||
END MODULE m
|
||||
|
||||
! { dg-final { cleanup-modules "m" } }
|
69
gcc/testsuite/gfortran.dg/typebound_operator_2.f03
Normal file
69
gcc/testsuite/gfortran.dg/typebound_operator_2.f03
Normal file
|
@ -0,0 +1,69 @@
|
|||
! { dg-do compile }
|
||||
! { dg-options "-w" }
|
||||
! FIXME: Remove -w once CLASS is fully supported.
|
||||
|
||||
! Type-bound procedures
|
||||
! Checks for correct errors with invalid OPERATOR/ASSIGNMENT usage.
|
||||
|
||||
MODULE m
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE t ! { dg-error "not yet implemented" }
|
||||
CONTAINS
|
||||
PROCEDURE, PASS :: onearg
|
||||
PROCEDURE, PASS :: onearg_alt => onearg
|
||||
PROCEDURE, PASS :: onearg_alt2 => onearg
|
||||
PROCEDURE, PASS :: threearg
|
||||
PROCEDURE, NOPASS :: noarg
|
||||
PROCEDURE, PASS :: sub
|
||||
PROCEDURE, PASS :: sub2 ! { dg-error "must be a FUNCTION" }
|
||||
PROCEDURE, PASS :: func
|
||||
|
||||
! These give errors at the targets' definitions.
|
||||
GENERIC :: OPERATOR(.AND.) => sub2
|
||||
GENERIC :: OPERATOR(*) => onearg
|
||||
GENERIC :: ASSIGNMENT(=) => func
|
||||
|
||||
GENERIC :: OPERATOR(.UOPA.) => sub ! { dg-error "must be a FUNCTION" }
|
||||
GENERIC :: OPERATOR(.UOPB.) => threearg ! { dg-error "at most, two arguments" }
|
||||
GENERIC :: OPERATOR(.UOPC.) => noarg ! { dg-error "at least one argument" }
|
||||
|
||||
GENERIC :: OPERATOR(.UNARY.) => onearg_alt
|
||||
GENERIC, PRIVATE :: OPERATOR(.UNARY.) => onearg_alt2 ! { dg-error "must have the same access" }
|
||||
END TYPE t
|
||||
|
||||
CONTAINS
|
||||
|
||||
INTEGER FUNCTION onearg (me) ! { dg-error "wrong number of arguments" }
|
||||
CLASS(t), INTENT(IN) :: me
|
||||
onearg = 5
|
||||
END FUNCTION onearg
|
||||
|
||||
INTEGER FUNCTION threearg (a, b, c)
|
||||
CLASS(t), INTENT(IN) :: a, b, c
|
||||
threearg = 42
|
||||
END FUNCTION threearg
|
||||
|
||||
INTEGER FUNCTION noarg ()
|
||||
noarg = 42
|
||||
END FUNCTION noarg
|
||||
|
||||
LOGICAL FUNCTION func (me, b) ! { dg-error "must be a SUBROUTINE" }
|
||||
CLASS(t), INTENT(OUT) :: me
|
||||
CLASS(t), INTENT(IN) :: b
|
||||
me = t ()
|
||||
func = .TRUE.
|
||||
END FUNCTION func
|
||||
|
||||
SUBROUTINE sub (a)
|
||||
CLASS(t), INTENT(IN) :: a
|
||||
END SUBROUTINE sub
|
||||
|
||||
SUBROUTINE sub2 (a, x)
|
||||
CLASS(t), INTENT(IN) :: a
|
||||
INTEGER, INTENT(IN) :: x
|
||||
END SUBROUTINE sub2
|
||||
|
||||
END MODULE m
|
||||
|
||||
! { dg-final { cleanup-modules "m" } }
|
Loading…
Add table
Reference in a new issue